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

718

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

Haacked
источник
4
В ASP.NET WebApi 2 параметры FromBody игнорируются для конечных точек HttpDelete.
Дженни О'Рейли
2
У меня похожая проблема, но у меня другой случай. Я хочу создать пакетный запрос на удаление, когда я хочу удалить сто объектов. Конечно, это большое повышение производительности для сетей до HTTP 2.0.
Singagirl
1
Были ли какие-либо изменения в HTTP / 2?
Джотман Сингх

Ответы:

570

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

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

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

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

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

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

  • Включено ли тело сообщения, зависит как от метода запроса, так и от статуса ответа (раздел 4.3).
  • тело сообщения явно запрещено в ответах на запросы головы (раздел 9, и в частности , 9.4)
  • тело сообщения явно запрещено в 1xx (информационный), 204 (без контента), и 304 (не изменяется) ответы (раздел 4.3)
  • все остальные ответы включают тело сообщения, хотя оно может иметь нулевую длину (раздел 4.3)
Томалак
источник
7
@ Джейсон Определенно. Вы также можете использовать пользовательские заголовки для передачи дополнительных данных, но почему бы не использовать тело запроса.
Томалак
86
Хотя спецификация не запрещает запросам DELETE иметь тело сообщения, раздел 4.3, по- видимому, указывает, что тело должно игнорироваться телом, так как не существует «определенной семантики» для тел объекта DELETE : «Сервер ДОЛЖЕН прочитать и переслать тело сообщения по любому запросу; если метод запроса не включает определенную семантику для тела объекта, то тело сообщения ДОЛЖНО игнорироваться при обработке запроса . "
Шелли
72
Обратите внимание, что многие клиенты также не могут отправить DELETE с телом. Это просто сжег меня на Android.
Кармический кодер
1
@ KarmicCoder: Отличный момент. Подробнее: Отправка HTTP-запроса на УДАЛЕНИЕ в Android .
MS Dousti
2
Много обсуждений о реализации, смешанной с HTTP-спецификацией. Клиенты будут реализовывать вещи так, как они интерпретируют спецификацию, не путайте это со смыслом спецификации. Дело в том, что спецификация оставляет это неоднозначным. Я не согласен с интерпретацией, что, поскольку не существует определенной семантики для тела-сущности, есть смысл, что ее следует игнорировать. Я думаю, что люди работают в обратном направлении от существующих конкретных интерпретаций клиентов (Джерси, тестовые клиенты Android и т. Д.) И пытаются оправдать интерпретацию, а не пытаться быть верными спецификации. Люди подвержены ошибкам.
Gibron
169

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

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

grzes
источник
3
последняя не утвержденная версия спецификации устраняет это требование. Последней утвержденной версией по-прежнему является RFC2616, указанный выше.
BishopZ
4
Какая версия? Версия 20 по-прежнему имеет ту же формулировку, что и версия 19, на которую я ссылался выше: «Тела в запросах DELETE не имеют определенной семантики. Обратите внимание, что отправка тела в запросе DELETE может привести к тому, что некоторые существующие реализации отклонят запрос».
выпадает
11
Версия 26 предполагает, что вы можете разрешить тело: 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.Итак, оно поставляется с предупреждением об обратной совместимости, оно предполагает, что в следующем стандарте будет сказано: «Да! DELETEможет иметь тело.
Pure.Krome
4
RFC 7231 раздел 4.3.5 завершает язык с версии 26 с A payload within a DELETE request message has no defined semantics. Так что тело разрешено.
mndrix
6
Тело разрешено, но не должно относиться к запросу. Там нет абсолютно никакого смысла в его использовании.
Эверт
55

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

evan.leonard
источник
2
Google App Engine создает и передает пустую сущность по умолчанию вместо тела запроса.
Оливер Хауслер
Дополнительная информация о Tomcat: Как заставить Apache Tomcat принимать метод DELETE .
MS Dousti
50

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

Вы читаете версию 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;
    }
}
Нил Макгиган
источник
15
Наличие тел в GET (и DELETE) явно плохо обращается с HTTP и REST. Существуют и другие механизмы управления параллелизмом (например, If-Modified-Since и etags).
Бруно
19
Как это ЯВНО плохо с ним обращаться, когда спецификация не запрещает тело в DELETE?
Нил Макгиган
5
Потому что ты не должен ничего делать с телом. См .: stackoverflow.com/a/983458/372643
Бруно
14
Это точно такая же проблема: GET позволяет вам получить представление ресурса, идентифицированного URI, а DELETE удаляет ресурс, идентифицированный URI. Используйте другой URI для других версий, если вы хотите удалить определенные версии. URI должен быть единственным идентификатором ресурса в HTTP / REST. Используйте метаданные в заголовках, если вам нужно обрабатывать параллелизм (например, If-Unmodified-Sinceили для Etagэтого они нужны ).
Бруно
5
Используйте заголовок ETag вместо поля версии в теле
malhal
26

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

Из раздела 4.3:

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

И раздел 9.7:

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

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

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

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

Адам Розенфилд
источник
19

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

Бен Фрид
источник
1
for whatever reason- потому что спецификация так говорит: P
Mardoxx
20
Спецификация не «говорит так», она просто говорит, что тело не определено конкретно. Если это не определено, и вы хотите игнорировать это, круто ... продолжайте и игнорируйте это. Но прямое отклонение запроса кажется крайним и ненужным.
Бен Фрид
1
Не полагайтесь на неопределенное поведение. Это довольно распространенная лучшая практика.
Эверт
@ Обратимся к явному неопределенному поведению (например, описанному в спецификациях языка Си), и такое поведение разрешено, но просто не описано. Использование тела сообщения DELETEявляется последним.
Альнитак
9

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

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

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

CleverPatrick
источник
7

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

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

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

Себастьян Лорбер
источник
1
Если вы используете Apache http-клиент, вы можете легко создавать свои собственные версии GET и DELETE, расширяя HttpEntityEnclosingRequestBase и заставляя метод getMethod () возвращать GET или DELETE. Мы используем это для общения с эластичным поиском.
Жиль ван Гурп
2
мертвая ссылка - отлично. нам нужно больше ответов на эти ссылки - нет
Котттон
3
Связанная документация теперь содержит только запросы POST, но не DELETE. Может быть стоит добавить примечание к этому ответу?
dshepherd
Elasticsearch также использует body с запросами GET.
Нидин Дэвид
7

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

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

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

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

И, наконец, причина не запрещающего тела:

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

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

Роберто Полли
источник
5

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

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

Саймон Джин
источник
В частности, RFC 7231 раздел 4.3.5
mndrix
3
Эта точная цитата уже была включена в предыдущие ответы, этот ответ следует удалить.
Madbreaks
5

Использование 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 Создает список на основе пользовательского запроса в теле.

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

Элиэзер Гарза
источник
Использование a POSTне является хорошим способом REST для создания новых ресурсов, потому что семантика ответов POST неясна, особенно в контексте заголовков Location. По сути, вы оставляете HTTP позади и ставите RPC сверху. Правильный «HTTP / REST путь» является создание ресурсов с использованием PUTж / If-None-Match: *заголовка (или spec'ing правильные методы HTTP, см и MKCOLт.д.).
HNH
4

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

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

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

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

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

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

выворачивать наизнанку
источник
2
«семантически бессмысленный» не означает то же самое, что «не имеет определенной семантики». Первое означает, что оно не может иметь никакого значения. Последнее просто означает, что сам RFC не указывает, какой может быть эта семантика. (Я пишу RFC)
Альнитак
1
Другими словами, если разработчик API желает определить некоторую семантику для себя, он совершенно свободен в этом.
Альнитак
1
@Alnitak это определенно неверное толкование. По этому определению любое тело HTTP-запроса не имеет определенной семантики, но DELETE и GET специально вызываются в спецификации. Вот фрагмент из еще
Evert
1
Я не согласен с вами, что это неясно в выпущенных в настоящий момент документах RFC, но если вы мне не верите, я бы пригласил вас спросить авторов об их намерениях по DELETE и GET. Вы обнаружите, что это соответствует моему ответу. Как и вы, я также участвую в работе органов по стандартизации, и я не просто одинокий человек с мнением о том, как следует интерпретировать RFC.
Эверт
2
Если это так, то 7231 плохо сформулирован и должен был сказать «тело полезной нагрузки ДОЛЖНО игнорироваться». На какой проект вы ссылаетесь выше?
Альнитак
3

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

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

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

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

Паркера
источник
Он реализован в последней версии Sahi Pro. Поскольку Sahi использует Java для выполнения HTTP-вызовов, а в Java была ошибка до версии 1.8, которая не позволяла пользователю сделать запрос DELETE. Таким образом, с Java 1.8 и Sahi Pro 6.1.1 (скоро будет доступно), люди могут сделать запрос DELETE с телом в Sahi.
Vivek V Dwivedi
-1

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

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

Ashish
источник
-1

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

Dattatray
источник
3
Они говорят о стандартах, а не о способностях. Вы даже можете получить запрос GET с телом, что не очень хорошо
ReZa