¿Se permite un cuerpo de entidad para una solicitud DELETE HTTP?

717

Al emitir una solicitud DELETE HTTP, el URI de la solicitud debe identificar completamente el recurso a eliminar. Sin embargo, ¿está permitido agregar metadatos adicionales como parte del cuerpo de la entidad de la solicitud?

Hackeado
fuente
44
En ASP.NET WebApi 2, los parámetros FromBody se ignoran para los puntos finales HttpDelete.
Jenny O'Reilly
2
Tengo una preocupación similar, pero mi caso es diferente. Quiero emitir una solicitud de eliminación por lotes cuando quiero eliminar cientos de objetos. Ciertamente, es un gran impulso de rendimiento para las redes pre HTTP 2.0.
Singagirl
1
¿Ha habido cambios en HTTP / 2?
Jyotman Singh

Respuestas:

570

La especificación no lo prohíbe o desalienta explícitamente, por lo que tendería a decir que está permitido.

Microsoft lo ve de la misma manera (puedo escuchar murmullos en la audiencia), declaran en el artículo de MSDN sobre el Método DELETE del Marco de Servicios de Datos ADO.NET :

Si una solicitud DELETE incluye un cuerpo de entidad, el cuerpo se ignora [...]

Además, esto es lo que RFC2616 (HTTP 1.1) tiene que decir con respecto a las solicitudes:

  • un cuerpo de entidad solo está presente cuando un cuerpo de mensaje (sección 7.2)
  • la presencia de un cuerpo de mensaje se señala mediante la inclusión de un encabezado Content-Lengtho Transfer-Encoding(sección 4.3)
  • no debe incluirse un cuerpo de mensaje cuando la especificación del método de solicitud no permite enviar un cuerpo de entidad (sección 4.3)
  • un cuerpo de entidad está explícitamente prohibido en solicitudes TRACE únicamente, todos los demás tipos de solicitud no están restringidos (sección 9 y 9.8 específicamente)

Para las respuestas, esto se ha definido:

  • si se incluye un cuerpo de mensaje depende tanto del método de solicitud como del estado de respuesta (sección 4.3)
  • se prohíbe explícitamente un cuerpo de mensaje en las respuestas a las solicitudes HEAD (sección 9 y 9.4 específicamente)
  • un cuerpo de mensaje está explícitamente prohibido en las respuestas 1xx (informativo), 204 (sin contenido) y 304 (no modificado) (sección 4.3)
  • todas las demás respuestas incluyen un cuerpo de mensaje, aunque puede ser de longitud cero (sección 4.3)
Tomalak
fuente
77
@ Jason Definitivamente. También puede usar encabezados personalizados para pasar datos adicionales, pero ¿por qué no usar el cuerpo de la solicitud?
Tomalak
86
Aunque la especificación no prohíbe que las solicitudes DELETE tengan un cuerpo de mensaje, la sección 4.3 parece indicar que los servidores deben ignorar el cuerpo ya que no hay una "semántica definida" para los cuerpos de entidad DELETE : "Un servidor DEBE leer y reenviar un cuerpo del mensaje en cualquier solicitud; si el método de solicitud no incluye una semántica definida para un cuerpo de entidad, entonces el cuerpo del mensaje DEBE ignorarse al manejar la solicitud ".
shelley
72
Tenga en cuenta que muchos clientes tampoco pueden enviar un DELETE con un cuerpo. Esto me quemó en Android.
Karmic Coder
1
@KarmicCoder: Gran punto. Más información: Envío de solicitud HTTP DELETE en Android .
MS Dousti
2
Mucha discusión sobre la implementación mezclada con la especificación HTTP. Los clientes implementarán las cosas en la forma en que interpretan la especificación, no confunda esto con el significado de la especificación. El hecho es que la especificación deja esto ambiguo. No estoy de acuerdo con la interpretación de que, dado que no existe una semántica definida para el cuerpo de la entidad, existe la implicación de que debe ignorarse. Creo que las personas están trabajando hacia atrás desde las interpretaciones específicas de los clientes que existen (Jersey, clientes de prueba de Android, etc.) y están tratando de justificar la interpretación en lugar de tratar de ser fieles a las especificaciones. Los humanos son falibles.
Gibron
169

La última actualización de la especificación HTTP 1.1 ( RFC 7231 ) permite explícitamente un cuerpo de entidad en una solicitud DELETE:

Una carga útil dentro de un mensaje de solicitud DELETE no tiene semántica definida; enviar un cuerpo de carga útil en una solicitud DELETE puede causar que algunas implementaciones existentes rechacen la solicitud.

grzes
fuente
3
La última versión no aprobada de la especificación elimina este requisito. La última versión aprobada sigue siendo la RFC2616 citada anteriormente.
BishopZ
44
¿Cual version? La versión 20 todavía tiene la misma redacción que la versión 19 que vinculé anteriormente: "Los cuerpos en solicitudes DELETE no tienen una semántica definida. Tenga en cuenta que enviar un cuerpo en una solicitud DELETE podría causar que algunas implementaciones existentes rechacen la solicitud".
Grzes
11
La versión 26 sugiere que puede permitir un cuerpo: por A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.lo que viene con una advertencia de compatibilidad con versiones anteriores, sugiere que el siguiente estándar dirá: '¡sí! DELETEpuede tener un cuerpo ».
Pure.Krome
44
RFC 7231 sección 4.3.5 finaliza el lenguaje de la versión 26 con A payload within a DELETE request message has no defined semantics. Entonces el cuerpo está permitido.
mndrix
66
El cuerpo está permitido pero no debe ser relevante para la solicitud. No tiene absolutamente ningún sentido usarlo.
Evert
55

Algunas versiones de Tomcat y Jetty parecen ignorar el cuerpo de una entidad si está presente. Lo que puede ser una molestia si pretendía recibirlo.

evan.leonard
fuente
2
Google App Engine crea instancias y pasa una entidad predeterminada vacía en lugar del cuerpo de la solicitud.
Oliver Hausler
Más información sobre Tomcat: Cómo hacer que Apache Tomcat acepte el método DELETE .
MS Dousti
50

Una razón para usar el cuerpo en una solicitud de eliminación es para un control de concurrencia optimista.

Has leído la versión 1 de un registro.

GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

Su colega lee la versión 1 del registro.

GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

Su colega cambia el registro y actualiza la base de datos, que actualiza la versión a 2:

PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }

Intenta eliminar el registro:

DELETE /some-resource/1 { id:1, version:1 }
409 Conflict

Debería obtener una excepción de bloqueo optimista. Vuelva a leer el registro, vea que es importante y tal vez no lo elimine.

Otra razón para usarlo es eliminar varios registros a la vez (por ejemplo, una cuadrícula con casillas de selección de filas).

DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content

Tenga en cuenta que cada mensaje tiene su propia versión. Tal vez pueda especificar múltiples versiones usando múltiples encabezados, pero por George, esto es más simple y mucho más conveniente.

Esto funciona en Tomcat (7.0.52) y Spring MVC (4.05), posiblemente también en versiones anteriores:

@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}
Neil McGuigan
fuente
15
Tener cuerpos en GET (y DELETE) claramente está maltratando HTTP y REST. Existen otros mecanismos para tratar el control de concurrencia (por ejemplo, If-Modified-Since y etags).
Bruno
19
¿Cómo es CLARAMENTE maltratarlo cuando la especificación no prohíbe el cuerpo en ELIMINAR?
Neil McGuigan
55
Porque no debes hacer nada con el cuerpo. Ver: stackoverflow.com/a/983458/372643
Bruno
14
Este es exactamente el mismo problema: GET le permite recuperar la representación del recurso identificado por el URI, y DELETE elimina el recurso identificado por el URI. Use un URI diferente para otras versiones si desea eliminar versiones específicas. El URI debe ser el único identificador del recurso en HTTP / REST. Use metadatos en los encabezados si necesita manejar la concurrencia (por ejemplo , If-Unmodified-Sinceo Etagpara eso están).
Bruno
55
Use el encabezado ETag en lugar de un campo de versión en un cuerpo
malhal
26

Me parece que RFC 2616 no especifica esto.

De la sección 4.3:

La presencia de un cuerpo de mensaje en una solicitud se señala mediante la inclusión de un campo de encabezado Content-Length o Transfer-Encoding en los encabezados de mensaje de la solicitud. Un cuerpo de mensaje NO DEBE incluirse en una solicitud si la especificación del método de solicitud (sección 5.1.1) no permite enviar un cuerpo de entidad en las solicitudes. Un servidor DEBE leer y reenviar un cuerpo de mensaje en cualquier solicitud; si el método de solicitud no incluye una semántica definida para un cuerpo de entidad, entonces el cuerpo del mensaje DEBE ignorarse al manejar la solicitud.

Y la sección 9.7:

El método DELETE solicita que el servidor de origen elimine el recurso identificado por el URI de solicitud. Este método PUEDE ser anulado por intervención humana (u otro medio) en el servidor de origen. No se puede garantizar al cliente que la operación se haya llevado a cabo, incluso si el código de estado devuelto por el servidor de origen indica que la acción se ha completado con éxito. Sin embargo, el servidor NO DEBE indicar éxito a menos que, en el momento en que se dé la respuesta, tenga la intención de eliminar el recurso o moverlo a una ubicación inaccesible.

Una respuesta exitosa DEBE ser 200 (OK) si la respuesta incluye una entidad que describe el estado, 202 (Aceptada) si la acción aún no se ha promulgado, o 204 (Sin contenido) si la acción se ha promulgado pero la respuesta no incluye una entidad.

Si la solicitud pasa a través de un caché y el URI de solicitud identifica una o más entidades actualmente en caché, esas entradas DEBERÍAN tratarse como obsoletas. Las respuestas a este método no se pueden almacenar en caché.

Por lo tanto, no está explícitamente permitido o no permitido, y existe la posibilidad de que un proxy en el camino elimine el cuerpo del mensaje (aunque DEBE leerlo y reenviarlo).

Adam Rosenfield
fuente
19

Solo un aviso, si proporciona un cuerpo en su solicitud DELETE y está utilizando un equilibrador de carga HTTPS de Google Cloud, rechazará su solicitud con un error 400. Estaba golpeándome la cabeza contra la pared y descubrí que Google, por cualquier razón, piensa que una solicitud ELIMINAR con un cuerpo es una solicitud con formato incorrecto.

Ben Fried
fuente
1
for whatever reason- porque la especificación lo dice: P
Mardoxx
20
La especificación no "lo dice", solo dice que el cuerpo no está específicamente definido. Si no está definido, y quieres ignorarlo, genial ... adelante, ignóralo. Pero rechazar la solicitud directamente parece extremo e innecesario.
Ben Fried
1
No confíe en comportamientos indefinidos. Es una práctica recomendada bastante común.
Evert
@Evert hay un comportamiento explícitamente indefinido (como se ve en las especificaciones del lenguaje C, por ejemplo) y hay un comportamiento permitido pero que simplemente no se describe. Usar un cuerpo de mensaje DELETEes lo último.
Alnitak
9

Vale la pena señalar que la especificación OpenAPI para la versión 3.0 dejó de admitir los métodos DELETE con un cuerpo:

ver aquí y aquí para referencias

Esto puede afectar su implementación, documentación o uso de estas API en el futuro.

CleverPatrick
fuente
7

Parece que ElasticSearch usa esto: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

Lo que significa que Netty admite esto.

Como se menciona en los comentarios, puede que ya no sea el caso

Sebastien Lorber
fuente
1
Si usa el cliente apache http, puede crear fácilmente sus propias versiones de GET y DELETE extendiendo HttpEntityEnclosingRequestBase y haciendo que el método getMethod () devuelva GET o DELETE. Usamos esto para hablar con Elasticsearch.
Jilles van Gurp
2
enlace muerto - genial. necesitamos más de esas respuestas de enlace - no
cottton
3
La documentación vinculada ahora contiene solo solicitudes POST, no DELETEs. ¿Podría valer la pena agregar una nota a esta respuesta?
dshepherd
Elasticsearch también usa body con solicitudes GET.
Nidhin David
7

Roy Fielding en la lista de correo HTTP aclara que en la lista de correo http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html y dice:

El cuerpo GET / DELETE tiene absolutamente prohibido tener algún impacto en el procesamiento o interpretación de la solicitud.

Esto significa que el cuerpo no debe modificar el comportamiento del servidor. Luego agrega:

además de la necesidad de leer y descartar los bytes recibidos para mantener el marco del mensaje.

Y finalmente, la razón para no prohibir el cuerpo:

La única razón por la que no prohibimos enviar un cuerpo es porque eso llevaría a implementaciones perezosas suponiendo que no se enviaría ningún cuerpo.

Entonces, si bien los clientes pueden enviar el cuerpo de la carga útil, los servidores deben descartarlo y las API no deben definir una semántica para el cuerpo de la carga útil en esas solicitudes.

Roberto Polli
fuente
5

Esto no está definido .

Una carga útil dentro de un mensaje de solicitud DELETE no tiene semántica definida; enviar un cuerpo de carga útil en una solicitud DELETE puede causar que algunas implementaciones existentes rechacen la solicitud.
https://tools.ietf.org/html/rfc7231#page-29

Simon Jin
fuente
Específicamente, RFC 7231 sección 4.3.5
mndrix
3
Esta cita exacta ya se incluyó en respuestas anteriores, esta respuesta debe eliminarse.
Madbreaks
5

Usar DELETE con un cuerpo es arriesgado ... Prefiero este enfoque para Operaciones de lista en lugar de REST:

Operaciones regulares

OBTENER / objetos / Obtiene todos los objetos

GET / object / ID Obtiene un objeto con ID especificado

POST / objetos agrega un nuevo objeto

PUT / object / ID Agrega un objeto con la ID especificada, actualiza un objeto

DELETE / object / ID Elimina el objeto con la ID especificada

Todas las acciones personalizadas son POST

POST / objects / addList Agrega una lista o matriz de objetos incluidos en el cuerpo

POST / objects / deleteList Elimina una lista de objetos incluidos en el cuerpo

POST / objects / customQuery Crea una lista basada en una consulta personalizada en el cuerpo

Si un cliente no admite sus operaciones extendidas, puede trabajar de la manera habitual.

Eliezer Garza
fuente
Usar a POSTno es una buena manera de RESTAR para crear nuevos recursos porque la semántica de las respuestas POST no está clara, especialmente en el contexto de los encabezados de Ubicación. Básicamente, está dejando atrás HTTP y apila RPC en la parte superior. La "forma HTTP / REST" adecuada es crear recursos utilizando PUTw / el If-None-Match: *encabezado (o especificando los métodos HTTP adecuados, ver MKCOLetc.).
hnh
4

No creo que se haya publicado una buena respuesta a esto, aunque ha habido muchos comentarios excelentes sobre las respuestas existentes. Levantaré la esencia de esos comentarios a una nueva respuesta:

Este párrafo de RFC7231 ha sido citado varias veces, lo que lo resume.

Una carga útil dentro de un mensaje de solicitud DELETE no tiene semántica definida; enviar un cuerpo de carga útil en una solicitud DELETE puede causar que algunas implementaciones existentes rechacen la solicitud.

Lo que extrañé de las otras respuestas fue la implicación. Sí, se permite incluir un cuerpo en las DELETEsolicitudes, pero carece de sentido semántico. Lo que esto realmente significa es que emitir una DELETEsolicitud con un cuerpo de solicitud es semánticamente equivalente a no incluir un cuerpo de solicitud.

La inclusión de un cuerpo de solicitud no debería tener ningún efecto en la solicitud, por lo que nunca tiene sentido incluirla.

tl; dr: técnicamente DELETEse permite una solicitud con un cuerpo de solicitud, pero nunca es útil hacerlo.

Evert
fuente
2
"semánticamente sin sentido" no significa lo mismo que "no tiene una semántica definida". Lo primero significa que no puede tener ningún significado. Esto último simplemente significa que el RFC en sí no especifica cuáles podrían ser esas semánticas. (Escribo RFC)
Alnitak
1
En otras palabras, si el implementador de una API desea definir alguna semántica por sí mismo, es perfectamente libre de hacerlo.
Alnitak
1
@Alnitak esta es definitivamente una mala interpretación. Según esa definición, cualquier cuerpo de solicitud HTTP no tiene una semántica definida, pero DELETE y GET se mencionan específicamente en la especificación. Aquí hay un fragmento de un borrador aún por publicar que habla sobre esto específicamente sobre la solicitud GET:
Evert
1
No estoy en desacuerdo con usted de que esto no está claro en los RFC publicados actualmente, pero si no me cree, lo invitaría a preguntar a los autores después de su intención de ELIMINAR y OBTENER. Encontrarás que se alinea con mi respuesta. Al igual que usted, también participo en organismos de normalización y no soy solo una persona solitaria con una opinión sobre cómo debe interpretarse la RFC.
Evert
2
Si ese es el caso, entonces 7231 está mal redactado y debería haber dicho "el cuerpo de la carga útil DEBE ser ignorado". ¿A qué borrador te refieres arriba?
Alnitak
3

En caso de que alguien se encuentre con este problema, No, no es universalmente compatible.

Actualmente estoy probando con Sahi Pro y es muy evidente que una llamada http DELETE elimina todos los datos del cuerpo proporcionados (una gran lista de ID para eliminar en masa según el diseño del punto final).

Me he puesto en contacto con ellos varias veces y he enviado tres paquetes separados de secuencias de comandos, imágenes y registros para que los revisen y aún no lo han confirmado. Un parche fallido y llamadas de conferencia perdidas por su apoyo más tarde y todavía no he recibido una respuesta sólida.

Estoy seguro de que Sahi no es compatible con esto, y me imagino que muchas otras herramientas siguen la suite.

Parker
fuente
Está implementado en la última versión de Sahi Pro. Dado que Sahi usa Java para hacer llamadas HTTP, y Java tenía un error antes de la versión 1.8 que no permite al usuario realizar una solicitud DELETE. Entonces, con Java 1.8 en adelante y Sahi Pro 6.1.1 (para ser público pronto), las personas pueden hacer una solicitud DELETE con cuerpo en Sahi.
Vivek V Dwivedi
-1

Podría ser la siguiente URL de GitHUb que te ayudará a obtener la respuesta. En realidad, el servidor de aplicaciones como Tomcat, Weblogic niega la llamada HTTP.DELETE con la carga útil de la solicitud. Entonces, teniendo en cuenta todas estas cosas, he agregado un ejemplo en github, por favor eche un vistazo a eso

https://github.com/ashish720/spring-examples

Ashish
fuente
-1

Pude implementar la operación DELETE con un cuerpo de Solicitud. Utilicé AWS Lambda y AWS API gateway y utilicé el lenguaje Go.

Dattatray
fuente
3
Están hablando de estándares, no de la habilidad. Incluso puede tener una solicitud GET con el cuerpo, lo que no es bueno
ReZa