При выдаче запроса HTTP DELETE URI запроса должен полностью идентифицировать ресурс для удаления. Однако допустимо ли добавлять дополнительные метаданные как часть сущности запроса?
При выдаче запроса HTTP DELETE URI запроса должен полностью идентифицировать ресурс для удаления. Однако допустимо ли добавлять дополнительные метаданные как часть сущности запроса?
Ответы:
Спецификация явно не запрещает и не препятствует этому, поэтому я бы сказал, что это разрешено.
Microsoft видит то же самое (я слышу ропот в аудитории), в статье MSDN говорится о методе DELETE в ADO.NET Data Services Framework :
Если запрос DELETE включает тело объекта, тело игнорируется [...]
Кроме того, вот что говорит RFC2616 (HTTP 1.1) в отношении запросов:
Content-Length
или Transfer-Encoding
(раздел 4.3)Для ответов это было определено:
Последнее обновление спецификации HTTP 1.1 ( RFC 7231 ) явно разрешает тело объекта в запросе DELETE:
Полезная нагрузка в сообщении запроса DELETE не имеет определенной семантики; отправка тела полезной нагрузки по запросу DELETE может привести к тому, что некоторые существующие реализации отклонят запрос.
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
может иметь тело.
A payload within a DELETE request message has no defined semantics
. Так что тело разрешено.
Некоторые версии 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;
}
}
If-Unmodified-Since
или для Etag
этого они нужны ).
Мне кажется, что RFC 2616 не определяет это.
Из раздела 4.3:
Присутствие тела сообщения в запросе сигнализируется включением поля заголовка Content-Length или Transfer-Encoding в заголовки сообщения запроса. Тело сообщения НЕ ДОЛЖНО быть включено в запрос, если спецификация метода запроса (раздел 5.1.1) не позволяет отправлять тело объекта в запросах. Сервер ДОЛЖЕН прочитать и переслать тело сообщения по любому запросу; если метод запроса не включает определенную семантику для тела объекта, то тело сообщения ДОЛЖНО игнорироваться при обработке запроса.
И раздел 9.7:
Метод DELETE запрашивает, чтобы исходный сервер удалил ресурс, указанный в Request-URI. Этот метод МОЖЕТ быть отменен вмешательством человека (или другими средствами) на исходном сервере. Клиент не может быть гарантирован, что операция была выполнена, даже если код состояния, возвращенный с исходного сервера, указывает, что действие было успешно выполнено. Однако серверу НЕ СЛЕДУЕТ указывать успех, если только во время ответа он не намерен удалить ресурс или переместить его в недоступное место.
Успешный ответ ДОЛЖЕН быть 200 (ОК), если ответ включает в себя объект, описывающий статус, 202 (Принят), если действие еще не было выполнено, или 204 (Нет содержимого), если действие было выполнено, но ответ не включает сущность.
Если запрос проходит через кеш, а Request-URI идентифицирует один или несколько кешируемых в данный момент объектов, эти записи ДОЛЖНЫ рассматриваться как устаревшие. Ответы на этот метод не кешируются.
Так что это явно не разрешено или не разрешено, и есть вероятность, что прокси-сервер по пути может удалить тело сообщения (хотя он ДОЛЖЕН прочитать и переслать его).
Просто наперед, если вы предоставите тело в своем запросе DELETE и используете балансировщик нагрузки HTTPS в облаке Google, он отклонит ваш запрос с ошибкой 400. Я ударился головой о стену и обнаружил, что Google по какой-то причине считает запрос DELETE с телом некорректным запросом.
for whatever reason
- потому что спецификация так говорит: P
DELETE
является последним.
Кажется, ElasticSearch использует это: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api
Что означает, что Netty поддерживает это.
Как упомянуто в комментариях, это может быть не так больше
Рой Филдинг в списке рассылки HTTP уточняет, что в списке рассылки http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html и говорит:
Тело GET / DELETE категорически запрещено оказывать какое-либо влияние на обработку или интерпретацию запроса.
Это означает, что тело не должно изменять поведение сервера. Затем он добавляет:
кроме необходимости читать и отбрасывать полученные байты, чтобы поддерживать кадрирование сообщения.
И, наконец, причина не запрещающего тела:
Единственная причина, по которой мы не запрещали отправку тела, заключается в том, что это приведет к отложенным реализациям, предполагающим, что тело не будет отправлено.
Поэтому, хотя клиенты могут отправлять тело полезной нагрузки, серверы должны его отбрасывать, а API не должны определять семантику для тела полезной нагрузки в этих запросах.
Это не определено .
Полезная нагрузка в сообщении запроса DELETE не имеет определенной семантики; отправка тела полезной нагрузки по запросу DELETE может привести к тому, что некоторые существующие реализации отклонят запрос.
https://tools.ietf.org/html/rfc7231#page-29
Использование 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 Создает список на основе пользовательского запроса в теле.
Если клиент не поддерживает ваши расширенные операции, он может работать в обычном режиме.
POST
не является хорошим способом REST для создания новых ресурсов, потому что семантика ответов POST неясна, особенно в контексте заголовков Location. По сути, вы оставляете HTTP позади и ставите RPC сверху. Правильный «HTTP / REST путь» является создание ресурсов с использованием PUT
ж / If-None-Match: *
заголовка (или spec'ing правильные методы HTTP, см и MKCOL
т.д.).
Я не думаю, что хороший ответ на это был опубликован, хотя было много хороших комментариев к существующим ответам. Я подниму суть этих комментариев в новый ответ:
Этот абзац из RFC7231 цитировался несколько раз, что подводит итог.
Полезная нагрузка в сообщении запроса DELETE не имеет определенной семантики; отправка тела полезной нагрузки по запросу DELETE может привести к тому, что некоторые существующие реализации отклонят запрос.
То, что я пропустил из других ответов, было значение. Да, разрешено включать тело в DELETE
запросах, но это семантически бессмысленно. На самом деле это означает, что отправка DELETE
запроса с телом запроса семантически эквивалентна отсутствию тела запроса.
Включение тела запроса не должно влиять на запрос, поэтому нет смысла включать его.
tl; dr: Технически DELETE
запрос с телом запроса разрешен, но делать это бесполезно.
В случае, если кто-то сталкивается с этой проблемой тестирования, Нет, это не универсально поддерживается.
В настоящее время я тестирую с Sahi Pro, и очень очевидно, что вызов http DELETE удаляет все предоставленные данные тела (большой список идентификаторов, которые нужно удалить в массе в соответствии с дизайном конечной точки).
Я связывался с ними несколько раз, а также отправил три отдельных пакета с записками, изображениями и журналами, чтобы они могли их просмотреть, и они до сих пор не подтвердили это. Неудачный патч и пропущенные конференц-звонки с их поддержкой позже, и я до сих пор не получил точного ответа.
Я уверен, что Sahi не поддерживает это, и я думаю, что многие другие инструменты следуют за набором.
Может быть, приведенный ниже URL-адрес GitHUb поможет вам получить ответ. На самом деле, сервер приложений, такой как Tomcat, Weblogic отклоняет вызов HTTP.DELETE с полезной нагрузкой запроса. Имея в виду все это, я добавил пример в github, пожалуйста, посмотрите на это