Posición autorizada de claves de consulta HTTP GET duplicadas

137

Tengo problemas para encontrar información autorizada sobre el comportamiento con los campos duplicados de la cadena de consulta HTTP GET, como

http://example.com/page?field=foo&field=bar 

y en particular si la orden se mantiene o no. La mayoría de los lenguajes orientados a la web producen una matriz que contiene foo y bar asociados a un "campo" clave, pero me gustaría saber si existe una declaración autorizada (por ejemplo, en un RFC) sobre este punto. RFC 3986 tiene una sección 3.4. Query, que se refiere a pares clave = valor, pero no se dice nada sobre cómo interpretar el orden y los campos duplicados, etc. Esto tiene sentido, ya que depende del backend y no está dentro del alcance de ese RFC ...

Aunque existe un estándar de facto, me gustaría ver una fuente autorizada para él, solo por curiosidad.

Stefano Borini
fuente
Me he estado preguntando sobre eso también. La otra cosa es la especificación sobre la fusión de los parámetros de la cadena de consulta con los del cuerpo POST.
Thilo
En el rancho de códigos, la gente dice que no hay garantía de pedido. Pero ese hilo es viejo y nadie lo respalda de ninguna manera: coderanch.com/t/357197/Servlets/java/getParameterValues-order
Thilo
1
Además de que el servidor mantiene el orden de la cadena de consulta, también existe la cuestión de que el navegador los envíe en orden DOM (o algún otro fijo).
Thilo el

Respuestas:

112

No hay especificaciones sobre esto. Puedes hacer lo que quieras.

Los enfoques típicos incluyen: primero dado, último dado, conjunto de todos, cadena de unión con coma de todos.

Supongamos que la solicitud sin procesar es:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

Luego, hay varias opciones para lo que request.query['tag']debería rendir, según el idioma o el marco:

request.query['tag'] => 'ruby'
request.query['tag'] => 'rails'
request.query['tag'] => ['ruby', 'rails']
request.query['tag'] => 'ruby,rails'
Yfeldblum
fuente
12
Más al punto de la pregunta, también existe la opción de ['rieles', 'rubí'] (orden diferente).
Thilo
2
Ciertamente se pueden hacer muchas cosas.
yfeldblum
77
.NET te dará como una matriz (no me importó el orden cuando lo probé), PHP te dará siempre el último y Java (al menos el sistema con el que trabajé basado en Java) siempre el primer valor. stackoverflow.com/questions/1809494/…
SimonSimCity
17
Esto se basa en un ataque llamado Contaminación de parámetros HTTP y ha sido analizado por OWASP: owasp.org/images/b/ba/AppsecEU09_CarettoniDiPaola_v0.8.pdf En la página 9 encontrará una lista de 20 sistemas y una descripción de cómo manejan este problema.
SimonSimCity
1
@SimonSimCity además de eso, PHP creará una matriz si agrega corchetes con un índice opcional al nombre del parámetro.
Martin Ender
14

Puedo confirmar que para PHP (al menos en la versión 4.4.4 y posteriores) funciona así:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

resultados en:

request.query['tag'] => 'rails'

Pero

GET /blog/posts?tag[]=ruby&tag[]=rails HTTP/1.1
Host: example.com

resultados en:

request.query['tag'] => ['ruby', 'rails']

Este comportamiento es el mismo para los datos GET y POST.

SimonSimCity
fuente
1
El []sufijo parece un comportamiento realmente extraño, pero si intentas enviar una matriz como argumento a través de jQuery .ajax(), las agregará automáticamente de la misma manera. Parece que esto beneficia a los usuarios de PHP.
Ian Clark
44
@IanClark Es intuitivo para los codificadores PHP: en PHP simple, se $foo[] = 1agrega a una matriz. Django (Python) también hace lo mismo.
Izkata
Puede verificar en Apache Tomcat que devuelve cadenas concatenadas por comas.
Gaurav Ojha
8

La respuesta de yfeldblum es perfecta.

Solo una nota sobre un quinto comportamiento que noté recientemente: en Windows Phone , abrir una aplicación con una uri con una clave de consulta duplicada dará como resultado NavegaciónFailed con:

System.ArgumentException: ya se ha agregado un elemento con la misma clave.

El culpable es System.Windows.Navigation.UriParsingHelper.InternalUriParseQueryStringToDictionary(Uri uri, Boolean decodeResults).

Por lo tanto, el sistema ni siquiera le permitirá manejarlo de la manera que desee, lo prohibirá. Te queda la única solución para elegir tu propio formato (CSV, JSON, XML, ...) y uri-escape-it.

Coeur
fuente
2
Eso parece un error interno de esa función, en lugar de una elección de diseño. La función probablemente no busca claves duplicadas en el Diccionario que está creando. Los diccionarios, por supuesto, requieren claves únicas.
gligoran
1
Entonces, ¿el navegador del cliente , no el servidor, arroja un error en esta situación? Parece un error. Me pregunto si este error todavía existe hoy.
Jon Schneider
1
@ JonSchneider Sí, el cliente está lanzando NavigationFailedpara tal URI. Pero, perdóname, abandoné el desarrollo de Windows (Phone) un mes después de esta publicación y me mudé a macOS (iOS), así que ya no puedo ayudar a rastrear este problema hoy en día.
Cœur
5

La mayoría (¿todos?) De los marcos no ofrecen garantías, así que suponga que se devolverán en orden aleatorio.

Siempre tome el enfoque más seguro.

Por ejemplo, la interfaz Java HttpServlet: ServletRequest.html # getParameterValues

Incluso el método getParameterMap omite cualquier mención sobre el orden de los parámetros (tampoco se puede confiar en el orden de un iterador java.util.Map).

Photodeus
fuente
3

Típicamente, valores de parámetros duplicados como

http://example.com/page?field=foo&field=bar

da como resultado un único parámetro queryString que es una matriz:

field[0]=='foo'
field[1]=='bar'

He visto este comportamiento en ASP, ASP.NET y PHP4.

3Dave
fuente
exactamente, este es el estándar de facto, pero por lo que veo no hay una decisión autorizada al respecto. Como no creo que este sea el caso, soy inepto para encontrarlo.
Stefano Borini
2
Sí, probablemente todos hayan visto ese comportamiento. La pregunta era si eso realmente se especifica en alguna parte.
Thilo
-1

Tenía la misma pregunta. Estoy escribiendo la función de JavaScript para analizar y stringificar consultas. No sé si una cadena de consulta tiene nombres duplicados o entre paréntesis, como x [] = 1 & x [] = 2, es estándar, aunque algunos idiomas admiten este formato.

Pero encuentro que Chrome y Firefox tienen una nueva Clase llamada URLSeachParamsy solo admite el formato más simple como name=value. Si hay nombres duplicados en la cadena de consulta, el getmétodo de URLSearchParamsdevolver solo el primero.

Entonces, personalmente, quizás una url más simple y sin nombres duplicados es mucho más segura para el futuro.

LCB
fuente
1
Si hay nombres duplicados en la cadena de consulta, el método get de URLSearchParams solo devuelve el primero. Esto no es correcto: puede recuperar todo el valor como una matriz usandoURLSearchParams.getAll('x')
Blaise
@Blaise Muchas gracias, no entendí la característica antes.
LCB