Должна ли RESTful-операция PUT вернуть что-то

437

Мне было интересно, что люди думают об PUTоперации RESTful, которая ничего не возвращает (ноль) в теле ответа.

AwkwardCoder
источник

Ответы:

615

Спецификация HTTP ( RFC 2616 ) имеет ряд рекомендаций, которые применимы. Вот моя интерпретация:

  • Код состояния HTTP 200 OKдля успешного PUT обновления существующего ресурса. Тело ответа не требуется. (Согласно Разделу 9.6 , 204 No Contentэто даже более уместно.)
  • Код состояния HTTP 201 Createdдля успешного PUT нового ресурса с наиболее конкретным URI для нового ресурса, возвращенного в поле заголовка Location, и любые другие соответствующие URI и метаданные ресурса, отраженные в теле ответа. ( RFC 2616, раздел 10.2.2 )
  • Код состояния HTTP 409 Conflictдля PUT, который не выполнен из-за модификации 3- й стороны, со списком различий между попыткой обновления и текущим ресурсом в теле ответа. ( RFC 2616, раздел 10.4.10 )
  • Код состояния HTTP 400 Bad Requestдля неудачного PUT, с текстом на естественном языке (например, на английском) в теле ответа, который объясняет причину сбоя PUT. ( RFC 2616, раздел 10.4 )
системная пауза
источник
25
@stian Интересно! Это кажется довольно самонадеянным со стороны Mozilla, так как я не могу найти ничего в RFC 2616 (особенно разделы 10.2 Successful 2xx и 10.2.1 200 OK ), которые конкретно исключают использование 200для PUT, DELETE или любого другого метода. Я что-то пропустил? Например, Мозилла становится боссом W3 и IETF? ;) А может, они просто никогда не слышали о принципе устойчивости Постеля.
система PAUSE
52
@stian: Это предложение было удалено 3 февраля 2013 года. Возможно, потому что кто-то читал об этом здесь. ;) developer.mozilla.org/en-US/docs/HTTP/…
Кристиан Штремпфер,
6
Семантика метода PUT состоит в том, чтобы игнорировать любое текущее состояние, в котором находится ресурс, поэтому возвращать конфликт 409 для PUT, который оказался неудачным из-за модификации третьей стороны, имеет смысл, только если запрос является условным.
Педро Вернек
8
@systemPAUSE Хороший ответ. Одно небольшое замечание: если вы не собираетесь возвращать тело ответа для успешной операции, я бы предложил использовать исключительно 204. Некоторые клиенты (например, jQuery Ajax) будут задыхаться, если они ожидают ответ ненулевой длины, но не получают его. Вы можете увидеть пример этого в этом вопросе .
nick_w
3
Возможно, RFC2616 был обновлен с момента получения ответа. Нет, где в 9.6 это упоминается No response body neededпо отношению к 200. Фактически тело ответа вообще не упоминается по отношению к PUT. Это только заявляетIf an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate successful completion of the request.
Джеймс
164

В отличие от большинства ответов здесь, я на самом деле думаю, что PUT должен возвращать обновленный ресурс (в дополнение к HTTP-коду, конечно).

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

LiorH
источник
3
«сервер также может применить некоторую обработку к этому ресурсу»: я новичок в этом. Это действительно RESTful?
Raedwald
22
@Raedwald уверен, что это так. REST не требует обновления всего ресурса в PUT, хотя обычно это рекомендуется. Некоторые поля могут не иметь смысла для обновления - например, дата создания или дата последнего изменения, вероятно, не должны быть включены в тело PUT, но, вероятно, будут изменены в результате PUT. С учетом сказанного я не согласен с LiorH в том, что PUT должен привести к возврату ресурса; Мне потребуется GET после PUT для получения обновленного ресурса.
Рандольфо
19
@Randolpho REST не требует, чтобы весь ресурс обновлялся на PUT, разве это не случай PATCH?
Марко Чамброне
14
@MarcoCiambrone Да, я согласен и отрекаюсь от предыдущего комментария. Я изменил свою мелодию на REST и PUT - PUT всегда должен быть идемпотентным и никогда не должен использоваться для частичного обновления. POST является единственной альтернативой, если не поддерживается PATCH, в этом случае PATCH может быть хорошей альтернативой. Однако PATCH - это новый глагол, который может не поддерживаться некоторыми серверными средами.
Рандольфо
2
Ответ был написан задолго до rfc7231, но в разделе 4.3.4 поясняется: «Метод PUT запрашивает, чтобы состояние целевого ресурса было создано или заменено на состояние, определенное представлением, заключенным в полезную нагрузку сообщения запроса»
aaaaaa
3

Я думаю, что сервер может вернуть содержимое в ответ на PUT. Если вы используете формат конверта ответа, который учитывает загруженные данные (например, формат, используемый данными ember), то вы также можете включить другие объекты, которые могли быть изменены с помощью триггеров базы данных и т. Д. (Загруженные данные явно уменьшают Количество запросов, и это кажется хорошим местом для оптимизации.)

Если я просто принимаю PUT и мне нечего сообщить, я использую код состояния 204 без тела. Если мне есть что сообщить, я использую код состояния 200 и включаю тело.

shaunc
источник
2

В спецификации HTTP / 1.1 (раздел 9.6) обсуждаются соответствующие коды ответа / ошибки. Однако это не относится к содержанию ответа.

Чего бы вы ожидали? Простой код ответа HTTP (200 и т. Д.) Кажется мне простым и недвусмысленным.

Брайан Агнью
источник
Да, но что делать, если вы хотите проверить, действительно ли вставленные данные в db после PUT или POST представляют собой истинные данные, которые вы хотите. Было бы лучше, если бы HTTP мог вернуть тело ответа.
tnkh
1
@tnkh, что вы предлагаете, совершенно ужасная идея. Сделайте отдельный вызов GET после успешного обновления, чтобы достичь того, что вы хотите. Чтобы обеспечить производительность, добавьте слой кэширования, если у вас есть проблемы в этом отделе. Мы не можем решить эти проблемы, возиться с логикой «все идет». Не связывайтесь с «твердыми» и базовыми принципами программирования, которые должны стать здравым смыслом в 2020 году. Это позор!
XDS
@XDS Я подтверждаю вашу первую часть комментария. Но не могу остановиться, чтобы закатить глаза после этого. Веселое комментарий
tnkh
Спасибо, что уточнили, почему вы находите это смешным, хотя.
XDS
2

Если серверная часть REST API является реляционной базой данных SQL, то

  1. Вы должны иметь RowVersion в каждой записи, которая может быть обновлена ​​(чтобы избежать проблемы потерянного обновления )
  2. Вы должны всегда возвращать новую копию записи после PUT (чтобы получить новый RowVersion ).

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

Джон Хенкель
источник
1

Http код ответа 201 для «Создано» вместе с заголовком «Местоположение», чтобы указать, где клиент может найти вновь созданный ресурс.

dc360
источник
5
Объекты PUT не являются (или не должны быть) вновь созданными ресурсами
kdazzle
9
@kdazzle PUT, безусловно, может быть недавно созданным ресурсом, и часто так и будет. w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6
Чарли
3
Просто, чтобы объяснить мой комментарий немного лучше. PUT означает, поместите этот элемент в это конкретное место, заменив то, что там в данный момент (если применимо).
user1751825
3
Да, ключевая фраза - «заменить то, что сейчас есть». Он должен уже существовать и его заменяют. PUT не должен быть для создания новых ресурсов.
Кевин М
3
@KevinM Как и в последнем документе RFC rfc7231 , в нем говорится, что ресурсы могут быть созданы: «Метод PUT запрашивает создание или замену состояния целевого ресурса [...]», и причина, по которой вы думаете, что PUT не может создать Новый ресурс связан с тем, что вы не обязательно знаете местоположение нового ресурса. Но если вы знаете его местоположение / идентификатор, его можно создать, если его еще нет.
Лев Лей
0

Я использовал RESTful API в своих сервисах, и вот мое мнение: сначала мы должны прийти к общему мнению: PUTиспользуется для обновления ресурса, а не для создания или получения.

Я определил ресурсы с помощью: Stateless resourceи Stateful resource:

  • Ресурсы без сохранения состояния Для этих ресурсов достаточно просто вернуть HttpCode с пустым телом, этого достаточно.

  • Ресурсы с отслеживанием состояния Например: версия ресурса. Для ресурсов такого типа вы должны указать версию, когда хотите ее изменить, поэтому верните полный ресурс или верните версию клиенту, чтобы клиенту не нужно было отправлять запрос на получение после действия обновления.

Но , для службы или системы, сохранить егоsimple,clearly,easy to use and maintainэто самое главное.

Брюс
источник
6
«PUT используется для обновления ресурса, а не для создания или получения». - это не правда и не распространено. По спецификации PUT может создать ресурс. Очистить = следуя общеизвестной спецификации.
Imre Pühvel
-3

Подобно тому, как пустое тело запроса соответствует первоначальной цели запроса GET, так и пустое тело ответа соответствует первоначальной цели запроса PUT.

AnthonyWJones
источник
-3

Кажется, все в порядке ... хотя я думаю, что элементарное указание успеха / неудачи / времени отправлено / # байт получено / и т.д. было бы предпочтительнее.

редактировать: я думал о целостности данных и / или ведении записей; метаданные, такие как хеш MD5 или метка времени для полученного времени, могут быть полезны для больших файлов данных.

Джейсон С
источник
1
Как насчет 200 ОК в заголовке ответа о статусе? Как ты думаешь, достаточно сказать: "Хорошо, спасибо?"
AnthonyWJones
заголовок ответа будет содержать код состояния, и на данном этапе мы говорим об HTTP :)
AwkwardCoder
-4

В идеале это вернет ответ об успехе / неудаче.

CGP
источник
13
Но не в теле ответа. Код состояния HTTP - место для этого. Возможно, в случае ошибки в ответном биде может быть возвращена некоторая расширенная информация об ошибке
The Archetypal Paul
-4

Существует разница между заголовком и телом ответа HTTP. PUT никогда не должен возвращать тело, но должен возвращать код ответа в заголовке. Просто выберите 200, если это было успешно, и 4xx, если нет. Нет такого понятия, как нулевой код возврата. почему ты хочешь сделать это?

AlexanderJohannesen
источник