Разрешено ли тело объекта для запроса HTTP DELETE?

При выдаче запроса HTTP DELETE URI запроса должен полностью идентифицировать ресурс для удаления. Однако допустимо ли добавлять дополнительные метаданные как часть сущности запроса?

18 ответов

Решение

Спецификация явно не запрещает и не препятствует этому, поэтому я бы сказал, что это разрешено.

Microsoft видит это так же (я слышу ропот в аудитории), они заявляют в статье MSDN о методе DELETE в ADO.NET Data Services Framework:

Если запрос DELETE включает тело объекта, тело игнорируется [...]

Кроме того, вот что RFC2616 (HTTP 1.1) должен сказать в отношении запросов:

  • тело объекта присутствует только в том случае, если тело сообщения присутствует (раздел 7.2)
  • присутствие тела сообщения сигнализируется включением Content-Length или же Transfer-Encoding заголовок (раздел 4.3)
  • тело сообщения не должно быть включено, если спецификация метода запроса не позволяет отправить тело объекта (раздел 4.3)
  • Тело сущности явно запрещено только в запросах TRACE, все остальные типы запросов не ограничены (в частности, разделы 9 и 9.8)

Для ответов это было определено:

  • Включено ли тело сообщения, зависит как от метода запроса, так и от статуса ответа (раздел 4.3).
  • тело сообщения явно запрещено в ответах на запросы HEAD (раздел 9, и 9.4 определенно)
  • тело сообщения явно запрещено в ответах 1xx (информационное), 204 (без содержимого) и 304 (не изменено) (раздел 4.3)
  • все остальные ответы включают тело сообщения, хотя оно может иметь нулевую длину (раздел 4.3)

Последнее обновление спецификации HTTP 1.1 ( RFC 7231) явно разрешает тело объекта в запросе DELETE:

Полезная нагрузка в сообщении запроса DELETE не имеет определенной семантики; отправка тела полезной нагрузки по запросу DELETE может привести к тому, что некоторые существующие реализации отклонят запрос.

Некоторые версии Tomcat и Jetty, похоже, игнорируют тело объекта, если оно присутствует. Что может быть неприятно, если вы намеревались получить его.

Одной из причин использования тела в запросе на удаление является оптимистичное управление параллелизмом.

Вы читаете версию 1 записи.

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

Ваш коллега читает версию 1 записи.

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

Ваш коллега меняет запись и обновляет базу данных, которая обновляет версию до 2:

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

Вы пытаетесь удалить запись:

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

Вы должны получить исключение оптимистичной блокировки. Перечитайте запись, увидите, что это важно, и, возможно, не удалите ее.

Другая причина его использования - удаление нескольких записей за раз (например, сетка с флажками выбора строк).

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

Обратите внимание, что каждое сообщение имеет свою версию. Возможно, вы можете указать несколько версий, используя несколько заголовков, но Джордж, это проще и намного удобнее.

Это работает в Tomcat (7.0.52) и Spring MVC (4.05), возможно, с более ранними версиями:

@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}

Просто напишите, если вы предоставите тело в своем запросе DELETE и используете балансировщик нагрузки HTTPS в облаке Google, он отклонит ваш запрос с ошибкой 400. Я ударился головой о стену и обнаружил, что Google по какой-то причине считает запрос DELETE с телом некорректным запросом.

Рой Филдинг в списке рассылки HTTP поясняет, что в списке рассылки http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html и говорит:

Тело GET/DELETE категорически запрещено оказывать какое-либо влияние на обработку или интерпретацию запроса.

Это означает, что тело не должно изменять поведение сервера. Затем он добавляет:

помимо необходимости читать и отбрасывать полученные байты, чтобы сохранить кадрирование сообщения.

И напоследок причина не запрещать тело:

Единственная причина, по которой мы не запретили отправку тела, заключается в том, что это приведет к ленивым реализациям, предполагающим, что тело не будет отправлено.

Таким образом, хотя клиенты могут отправлять тело полезной нагрузки, серверы должны отбрасывать его, а API не должны определять семантику тела полезной нагрузки для этих запросов.

Мне кажется, что RFC 2616 не определяет это.

Из раздела 4.3:

Присутствие тела сообщения в запросе сигнализируется включением поля заголовка Content-Length или Transfer-Encoding в заголовки сообщения запроса. Тело сообщения НЕ ДОЛЖНО быть включено в запрос, если спецификация метода запроса (раздел 5.1.1) не позволяет отправлять тело объекта в запросах. Сервер ДОЛЖЕН прочитать и переслать тело сообщения по любому запросу; если метод запроса не включает определенную семантику для тела объекта, то тело сообщения ДОЛЖНО игнорироваться при обработке запроса.

И раздел 9.7:

Метод DELETE запрашивает, чтобы исходный сервер удалил ресурс, указанный в Request-URI. Этот метод МОЖЕТ быть отменен вмешательством человека (или другими средствами) на исходном сервере. Клиент не может быть гарантирован, что операция была выполнена, даже если код состояния, возвращенный с исходного сервера, указывает, что действие было успешно выполнено. Однако серверу НЕ СЛЕДУЕТ указывать успех, если только во время ответа он не намерен удалить ресурс или переместить его в недоступное место.

Успешный ответ ДОЛЖЕН быть 200 (ОК), если ответ включает в себя объект, описывающий статус, 202 (Принятый), если действие еще не было принято, или 204 (Нет содержимого), если действие было выполнено, но ответ не включает сущность.

Если запрос проходит через кеш, а Request-URI идентифицирует один или несколько кешируемых в данный момент объектов, эти записи ДОЛЖНЫ рассматриваться как устаревшие. Ответы на этот метод не кешируются.

Так что это явно не разрешено или не разрешено, и есть вероятность, что прокси по пути может удалить тело сообщения (хотя оно ДОЛЖНО прочитать и переслать его).

Я не думаю, что хороший ответ на этот вопрос был опубликован, хотя было много хороших комментариев к существующим ответам. Я подниму суть этих комментариев в новый ответ:

Этот абзац из RFC7231 цитировался несколько раз, что подводит итог.

Полезная нагрузка в сообщении запроса DELETE не имеет определенной семантики; отправка тела полезной нагрузки по запросу DELETE может привести к тому, что некоторые существующие реализации отклонят запрос.

То, что я пропустил из других ответов, было значение. Да, разрешено включать тело на DELETE запросы, но это семантически бессмысленно. Что это действительно означает, что выдача DELETE запрос с телом запроса семантически эквивалентен отсутствию тела запроса.

Включение тела запроса не должно влиять на запрос, поэтому нет смысла его включать.

TL; Dr: Технически DELETE запрос с телом запроса разрешен, но это бесполезно.

Использование DELETE с Body является рискованным... Я предпочитаю такой подход для операций со списками, а не для REST:

Регулярные операции

GET / objects / Получает все объекты

GET / object /ID Получает объект с указанным идентификатором

POST / objects Добавляет новый объект

PUT / object /ID Добавляет объект с указанным идентификатором, обновляет объект

DELETE / object /ID Удаляет объект с указанным идентификатором

Все пользовательские действия POST

POST / objects /addList Добавляет список или массив объектов, включенных в тело

POST / objects /deleteList Удаляет список объектов, включенных в тело

POST / objects /customQuery Создает список на основе пользовательского запроса в теле.

Если клиент не поддерживает ваши расширенные операции, он может работать в обычном режиме.

Стоит отметить, что в спецификации OpenAPI для версии 3.0 отсутствует поддержка методов DELETE с телом:

смотрите здесь и здесь для ссылок

Это может повлиять на вашу реализацию, документацию или использование этих API в будущем.

Кажется, ElasticSearch использует это: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html

Что означает, что Netty поддерживает это.

Как упомянуто в комментариях, это может быть не так больше

В нескольких других ответах упоминается RFC 7231, в котором фактически говорится, чтоDELETEзапросу разрешено иметь тело, но это не рекомендуется.

В 2022 году RFC 7231 был заменен RFC 9110: HTTP Semantics , в котором теперь говорится:

[...] содержимое, полученное в запросе DELETE, не имеет общеопределенной семантики, не может изменить значение или цель запроса и может привести к тому, что некоторые реализации отклонят запрос и закроют соединение [...]. Клиент НЕ ДОЛЖЕН генерировать контент в запросе DELETE, если только он не направлен непосредственно на исходный сервер, который ранее указал, внутри или вне диапазона, что такой запрос имеет цель и будет адекватно поддерживаться. Исходный сервер НЕ ДОЛЖЕН полагаться на частные соглашения для получения контента, поскольку участники HTTP-коммуникации часто не знают о посредниках в цепочке запросов.

Этот язык был усилен по сравнению с предыдущим языком, чтобы сказать, что, несмотря на то, что он разрешен, вам действительно нужно быть очень осторожным при его использовании, потому что (например) некоторые пользователи могут быть за прокси-сервером, который удалит тело из запроса в в целях борьбы с «запросной контрабандой».

Это не определено.

Полезная нагрузка в сообщении запроса DELETE не имеет определенной семантики; отправка тела полезной нагрузки по запросу DELETE может привести к тому, что некоторые существующие реализации отклонят запрос.
https://tools.ietf.org/html/rfc7231

В случае, если кто-то сталкивается с этой проблемой тестирования, Нет, это не универсально поддерживается.

В настоящее время я тестирую с Sahi Pro, и совершенно очевидно, что вызов http DELETE удаляет все предоставленные данные тела (большой список идентификаторов, которые нужно массово удалить согласно схеме конечных точек).

Я связывался с ними несколько раз, а также отправил три отдельных пакета с записками, изображениями и журналами, чтобы они могли их просмотреть, и они до сих пор не подтвердили это. Неудачный патч и пропущенные конференц-звонки с их поддержкой позже, и я до сих пор не получил точного ответа.

Я уверен, что Sahi не поддерживает это, и я думаю, что многие другие инструменты следуют за набором.

Практический ответ: НЕТ

Некоторые клиенты и серверы игнорируют или даже удаляют тело запроса DELETE. В некоторых редких случаях они не работают и возвращают ошибку.

Мне удалось реализовать операцию УДАЛИТЬ с телом запроса. Я использовал AWS Lambda и AWS API gateway и использовал язык Go.

Как отмечалось в других ответах, использование тела запроса с запросом... в лучшем случае сомнительно....

В RFC 9110 говорится:

Клиент НЕ ДОЛЖЕН генерировать контент в запросе DELETE, если только он не направлен непосредственно на исходный сервер, который ранее указал внутри или вне сети, что такой запрос имеет цель и будет адекватно поддерживаться .

Я хочу указать как минимум на одну реализацию, где действительно требуется тело запроса :

REST API Spotify для удаления треков из плейлиста
https://developer.spotify.com/documentation/web-api/reference/remove-tracks-playlist

Это HTTPDELETEзапрос, тело которого представляет собой документ JSON, в котором указаны треки, которые нужно удалить, и снимок, из которого их нужно удалить.

Может быть, приведенный ниже URL-адрес GitHUb поможет вам получить ответ. На самом деле, сервер приложений, такой как Tomcat, Weblogic отклоняет вызов HTTP.DELETE с полезной нагрузкой запроса. Имея в виду все это, я добавил пример в github, пожалуйста, посмотрите на это

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

Другие вопросы по тегам