Estoy desarrollando un nuevo servicio web RESTful para nuestra aplicación.
Al hacer un GET en ciertas entidades, los clientes pueden solicitar el contenido de la entidad. Si desean agregar algunos parámetros (por ejemplo, ordenar una lista), pueden agregar estos parámetros en la cadena de consulta.
Alternativamente, quiero que las personas puedan especificar estos parámetros en el cuerpo de la solicitud. HTTP / 1.1 no parece prohibir esto explícitamente. Esto les permitirá especificar más información, podría facilitar la especificación de solicitudes XML complejas.
Mis preguntas:
- ¿Es esta una buena idea por completo?
- ¿Tendrán problemas los clientes HTTP con el uso de cuerpos de solicitud dentro de una solicitud GET?
Respuestas:
Comentario de Roy Fielding sobre incluir un cuerpo con una solicitud GET .
Sí, puede enviar un cuerpo de solicitud con GET pero no debería tener ningún significado. Si le da sentido al analizarlo en el servidor y cambiar su respuesta en función de su contenido , entonces está ignorando esta recomendación en la especificación HTTP / 1.1, sección 4.3 :
Y la descripción del método GET en la especificación HTTP / 1.1, sección 9.3 :
que establece que el cuerpo de la solicitud no es parte de la identificación del recurso en una solicitud GET, solo el URI de la solicitud.
Actualización El RFC2616 al que se hace referencia como "especificación HTTP / 1.1" ahora está obsoleto. En 2014 fue reemplazado por RFC 7230-7237. Se ha eliminado la cita "el cuerpo del mensaje DEBE ignorarse al manejar la solicitud". Ahora es solo "La estructura de mensajes de solicitud es independiente de la semántica del método, incluso si el método no define ningún uso para un cuerpo de mensaje" La segunda cita "El método GET significa recuperar cualquier información ... identificada por el URI de solicitud" fué borrado. - De un comentario
fuente
Si bien puede hacerlo, en la medida en que no esté explícitamente excluido por la especificación HTTP, sugeriría evitarlo simplemente porque la gente no espera que las cosas funcionen de esa manera. Hay muchas fases en una cadena de solicitud HTTP y, si bien "en su mayoría" se ajustan a la especificación HTTP, lo único seguro es que se comportarán como los navegadores web utilizan tradicionalmente. (Estoy pensando en cosas como proxies transparentes, aceleradores, kits de herramientas de A / V, etc.)
Este es el espíritu detrás del Principio de Robustez: "sé liberal en lo que aceptas y conservador en lo que envías", no quieres empujar los límites de una especificación sin una buena razón.
Sin embargo, si tiene una buena razón, hágalo.
fuente
Es probable que encuentre problemas si alguna vez intenta aprovechar el almacenamiento en caché. Los proxies no van a mirar en el cuerpo GET para ver si los parámetros tienen un impacto en la respuesta.
fuente
Ni restclient ni la consola REST lo admiten, pero curl sí.
La especificación HTTP dice en la sección 4.3
La sección 5.1.1 nos redirige a la sección 9.x para los diversos métodos. Ninguno de ellos prohíbe explícitamente la inclusión de un cuerpo de mensaje. Sin embargo...
La sección 5.2 dice
y la Sección 9.3 dice
Lo que en conjunto sugiere que cuando se procesa una solicitud GET, no se requiere que un servidor examine nada más que el campo URI de solicitud y encabezado de host.
En resumen, la especificación HTTP no le impide enviar un cuerpo de mensaje con GET, pero hay suficiente ambigüedad que no me sorprendería si no fuera compatible con todos los servidores.
fuente
GET /contacts/100/addresses
devuelve una colección de direcciones para la persona conid=100
.Elasticsearch acepta solicitudes GET con un cuerpo. Incluso parece que esta es la forma preferida: guía Elasticsearch
Algunas bibliotecas de clientes (como el controlador Ruby) pueden registrar el comando cry en stdout en modo de desarrollo y está utilizando esta sintaxis ampliamente.
fuente
curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'
es equivalente a incluir la carga útil comosource
parámetro:curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
Lo que está tratando de lograr se ha hecho durante mucho tiempo con un método mucho más común, y uno que no depende del uso de una carga útil con GET.
Simplemente puede crear su tipo de medio de búsqueda específico, o si desea ser más RESTful, use algo como OpenSearch y PUBLIQUE la solicitud al URI que el servidor le indicó, digamos / search. El servidor puede generar el resultado de búsqueda o construir el URI final y redirigir usando un 303.
Esto tiene la ventaja de seguir el método PRG tradicional, ayuda a los intermediarios de caché a almacenar los resultados, etc.
Dicho esto, los URI se codifican de todos modos para cualquier cosa que no sea ASCII, y también lo son application / x-www-form-urlencoded y multipart / form-data. Recomiendo usar esto en lugar de crear otro formato json personalizado si su intención es admitir escenarios ReSTful.
fuente
Puedes enviar un GET con un cuerpo o enviar un POST y renunciar a la religiosidad RESTish (no es tan malo, hace 5 años solo había un miembro de esa fe: sus comentarios se vincularon anteriormente).
Tampoco son buenas decisiones, pero enviar un cuerpo GET puede evitar problemas para algunos clientes y algunos servidores.
Hacer una POST puede tener obstáculos con algunos marcos RESTish.
Julian Reschke sugirió anteriormente usar un encabezado HTTP no estándar como "BÚSQUEDA" que podría ser una solución elegante, excepto que es aún menos probable que sea compatible.
Puede ser más productivo enumerar clientes que pueden y no pueden hacer cada uno de los anteriores.
Clientes que no pueden enviar un GET con cuerpo (que yo sepa):
Clientes que pueden enviar un GET con cuerpo:
Servidores y bibliotecas que pueden recuperar un cuerpo de GET:
Servidores (y servidores proxy) que despojan a un cuerpo de GET:
fuente
SEARCH
método posiblemente se rompería en el camino? Si los proxies no entienden un método, se espera que lo pasen como están, así que no estoy muy seguro de por qué crees que rompería algo ...Le hice esta pregunta al IETF HTTP WG. El comentario de Roy Fielding (autor del documento http / 1.1 en 1998) fue que
RFC 7213 (HTTPbis) establece:
Parece claro ahora que la intención era que el significado semántico en los cuerpos de solicitud GET está prohibido, lo que significa que el cuerpo de la solicitud no puede usarse para afectar el resultado.
Hay representantes que definitivamente romperán su solicitud de varias maneras si incluye un cuerpo en GET.
En resumen, no lo hagas.
fuente
Google, por ejemplo, está peor que ignorarlo, ¡lo considerará un error !
Pruébelo usted mismo con un simple netcat:
(el contenido de 1234 es seguido por CR-LF, por lo que es un total de 6 bytes)
y obtendrás:
También obtienes 400 Bad Request de Bing, Apple, etc. que son atendidos por AkamaiGhost.
Por lo tanto, no recomendaría usar solicitudes GET con una entidad del cuerpo.
fuente
GET
solicitudes, es porque su propio servidor personalizado puede manejarlo. La pregunta es si las otras "partes móviles" (navegadores, cachés, etc.) funcionarán correctamente.GET
punto final en particular ; no tiene nada que ver con el usoGET
en el caso general. Una carga útil aleatoria podría dividirse con laPOST
misma facilidad y devolver la misma400 Bad Request
si el contenido no estuviera en un formato que tuviera sentido en el contexto de la solicitud específica.De RFC 2616, sección 4.3 , "Cuerpo del mensaje":
Es decir, los servidores siempre deben leer cualquier cuerpo de solicitud proporcionado de la red (verifique Content-Length o lea un cuerpo fragmentado, etc.). Además, los representantes deben reenviar cualquier cuerpo de solicitud que reciban. Luego, si el RFC define la semántica para el cuerpo para el método dado, el servidor puede usar el cuerpo de la solicitud para generar una respuesta. Sin embargo, si el RFC no define la semántica para el cuerpo, entonces el servidor debería ignorarlo.
Esto está en línea con la cita de Fielding anterior.
La Sección 9.3 , "GET", describe la semántica del método GET y no menciona los cuerpos de solicitud. Por lo tanto, un servidor debe ignorar cualquier cuerpo de solicitud que reciba en una solicitud GET.
fuente
Según XMLHttpRequest, no es válido. De la norma :
Aunque, no creo que deba, porque la solicitud GET podría necesitar un gran contenido corporal.
Entonces, si confía en XMLHttpRequest de un navegador, es probable que no funcione.
fuente
Si realmente desea enviar un cuerpo JSON / XML almacenable en caché a la aplicación web, el único lugar razonable para colocar sus datos es una cadena de consulta codificada con RFC4648: codificación Base 64 con URL y alfabeto seguro de nombre de archivo . Por supuesto, podría simplemente urlencode JSON y poner en el valor del parámetro de URL, pero Base64 da un resultado más pequeño. Tenga en cuenta que existen restricciones de tamaño de URL, consulte ¿Cuál es la longitud máxima de una URL en diferentes navegadores? .
Puede pensar que el
=
carácter de relleno de Base64 puede ser malo para el valor de parámetro de URL, sin embargo, parece que no; consulte esta discusión: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . Sin embargo, no debe colocar datos codificados sin el nombre de parámetro porque la cadena codificada con relleno se interpretará como clave de parámetro con valor vacío. Me gustaría utilizar algo así como?_b64=<encodeddata>
.fuente
Vary
encabezado, no era consciente de su potencial real.No recomendaría esto, va en contra de las prácticas estándar y no ofrece mucho a cambio. Desea conservar el cuerpo para el contenido, no para las opciones.
fuente
¿Qué pasa con los encabezados codificados base64 no conformes? "ALGUNOS PARAMS DE APLICACIÓN: sdfSD45fdg45 / aS"
Restricciones de longitud hm. ¿No puedes hacer que tu manejo POST distinga entre los significados? Si desea parámetros simples como la ordenación, no veo por qué esto sería un problema. Supongo que es certeza lo que te preocupa.
fuente
x-
prefijo, cualquier límite en la longitud de los encabezados sería completamente un límite arbitrario del servidor.Estoy molesto porque REST ya que el protocolo no admite OOP y el
Get
método es una prueba. Como solución, puede serializar su DTO a JSON y luego crear una cadena de consulta. En el lado del servidor, podrá deserializar la cadena de consulta al DTO.Echa un vistazo a:
El enfoque basado en mensajes puede ayudarlo a resolver la restricción del método Get. Podrá enviar cualquier DTO como con el cuerpo de la solicitud
El marco del servicio web Nelibur proporciona una funcionalidad que puede usar
fuente
Por ejemplo, funciona con Curl, Apache y PHP.
Archivo PHP:
Comando de consola:
Salida:
fuente
$_POST
cuando el cuerpo se envíe con una solicitud POST yapplication/x-www-form-urlencoded
. Eso significa que el cuerpo se ignora en unaGET
solicitud. En este caso:$_GET
y de$_POST
todos modos son muy engañosos en este momento. Así que mejor usophp://input
En mi humilde opinión, puede enviar el
JSON
codificado (es decirencodeURIComponent
) en elURL
, de esta manera no viola lasHTTP
especificaciones y lleva suJSON
al servidor.fuente
Tiene una lista de opciones que son mucho mejores que usar un cuerpo de solicitud con GET.
Supongamos que tiene categorías y elementos para cada categoría. Ambos serán identificados por una identificación ("catid" / "itemid" por el bien de este ejemplo). Desea ordenar de acuerdo con otro parámetro "sortby" en un "orden" específico. Desea pasar parámetros para "sortby" y "order":
Usted puede:
example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
example.com/category/{catid}/item/{itemid}/{sortby}/{order}
Todos tienen sus desventajas, pero son mucho mejores que usar un GET con un cuerpo.
fuente
Incluso si una herramienta popular usa esto, como se cita frecuentemente en esta página, creo que sigue siendo una mala idea, ya que es demasiado exótica, a pesar de que no está prohibida por la especificación.
Muchas infraestructuras intermedias pueden simplemente rechazar tales solicitudes.
Por ejemplo, olvidarse de utilizar algunos de los CDN disponible en frente de su sitio web, como este uno :
Y sí, es posible que las bibliotecas de sus clientes tampoco admitan la emisión de tales solicitudes, como se informa en este comentario .
fuente
Estoy usando el RestTemplate de Spring Framework en mi programa cliente y, en el lado del servidor, definí una solicitud GET con un cuerpo Json. Mi propósito principal es el mismo que el suyo: cuando la solicitud tiene numerosos parámetros, ponerlos en el cuerpo parece más ordenado que ponerlos en la cadena de URI prolongada. ¿Si?
Pero, lamentablemente, ¡no está funcionando! El lado del servidor lanzó la siguiente excepción:
org.springframework.http.converter.HttpMessageNotReadableException: falta el cuerpo de solicitud requerido ...
Pero estoy bastante seguro de que el código del cliente proporciona correctamente el cuerpo del mensaje, entonces, ¿qué pasa?
Seguí el método RestTemplate.exchange () y encontré lo siguiente:
Tenga en cuenta que en el método executeInternal (), el argumento de entrada 'bufferedOutput' contiene el cuerpo del mensaje proporcionado por mi código. Lo vi a través del depurador.
Sin embargo, debido a prepareConnection (), getDoOutput () en executeInternal () siempre devuelve falso, lo que a su vez hace que el bufferedOutput sea completamente ignorado. No se copia en la secuencia de salida.
En consecuencia, mi programa de servidor no recibió el cuerpo del mensaje y lanzó esa excepción.
Este es un ejemplo sobre el RestTemplate del marco Spring. El punto es que, incluso si el cuerpo del mensaje ya no está prohibido por la especificación HTTP, algunas bibliotecas o marcos de clientes o servidores aún pueden cumplir con la especificación anterior y rechazar el cuerpo del mensaje de la solicitud GET.
fuente