Создайте запрос с помощью POST с кодами ответа 200 или 201 и содержимым

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

Я планирую отправить сообщение на

http://myhost/serviceX/someResources

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

Я просматриваю определения кодов ответа HTTP и вижу эти возможности :

200: вернуть объект, описывающий или содержащий результат действия;

201: что означает СОЗДАН. Значение * Запрос был выполнен, и в результате был создан новый ресурс. На вновь созданный ресурс можно ссылаться с помощью URI, возвращаемого в сущности ответа, с наиболее конкретным URI для ресурса, заданным полем заголовка Location. В ответ СЛЕДУЕТ включать объект, содержащий список характеристик ресурсов и местоположений, из которых пользователь или пользовательский агент может выбрать наиболее подходящий. Формат объекта определяется типом носителя, указанным в поле заголовка Content-Type. *

Последнее звучит больше в соответствии со спецификацией Http, но я не совсем понимаю, что

Ответ ДОЛЖЕН включать объект, содержащий список характеристик ресурса и местоположения (а).

средства.

Рекомендации? Интерпретации?


person djna    schedule 07.12.2009    source источник


Ответы (7)


Идея состоит в том, что тело ответа дает вам страницу, которая связывает вас с этим:

201 Создано

Код состояния 201 (Создан) указывает, что запрос был выполнен и привел к созданию одного или нескольких новых ресурсов. Первичный ресурс, созданный запросом, идентифицируется либо полем заголовка Location в ответе, либо, если поле Location не получено, действующим URI запроса.

Это означает, что вы должны включить Location в заголовок ответа, который дает URL-адрес, по которому вы можете найти только что созданный объект:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Тело ответа

Затем они упоминают, что вы должны включить в ответ body:

Полезные данные ответа 201 обычно описывают созданные ресурсы и ссылаются на них.

Человеку, использующему браузер, вы даете ему то, на что он может взглянуть, и щелкаете мышью, чтобы перейти к вновь созданному ресурсу:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="/a/36373586/12597">here</A> to view it.

Если страница будет использоваться только роботом, имеет смысл сделать так, чтобы ответ был машиночитаемым:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

Или, если хотите:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

Ответ полностью зависит от вас; это произвольно, что вы хотите.

Дружественный к кешу

Наконец, есть оптимизация, заключающаяся в том, что я могу предварительно кэшировать созданный ресурс (потому что у меня уже есть контент; я только что загрузил его). Сервер может вернуть дату или ETag, которые я могу сохранить вместе с только что загруженным мной контентом:

См. раздел 7.2 для обсуждения значения и цели полей заголовка валидатора, таких как как ETag и Last-Modified в ответе 201.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="/a/36373586/12597">here</A> to view it.

А ETag - чисто произвольные значения. Все, что имеет значение, - это их отличия при изменении ресурса (и необходимости обновления кешей). ETag обычно является хешем (например, SHA2-256). Но это может быть база данных rowversion или увеличивающийся номер версии. Все, что изменится, когда вещь изменится.

person Ian Boyd    schedule 02.04.2016
comment
Пока что ваш ответ кажется наиболее разумным. Меня немного беспокоит онтология ответа, но в остальном это кажется наиболее зрелой интерпретацией спецификации. Мне любопытно, есть ли какой-нибудь легкий способ реагирования на обработку человеком / машиной. но в основном я заинтригован тем, что вы кешируете свое собственное предложение ввода. Большинство известных мне веб-приложений не будут создавать версию ресурса 1: 1. Даже если это что-то тривиальное, например, нормализация заглавных букв в строке. Разве не сложно рассматривать вашу отправленную версию как версию, для которой был создан etag? - person Anthony; 30.08.2016
comment
@Anthony, кеширование: это может быть своего рода приложение для хранения файлов 1: 1. Сравните, например, WebDAV PUT & POST. Огромные файлы, которые нужно обрабатывать. - person kxr; 12.05.2017
comment
@Anthony. Вам решать, хотите ли вы вернуть ETag обратно клиенту. Если содержимое, только что загруженное клиентом, не является тем, что вы сохранили, не возвращайте ETag. Это ваша гибкость и ваш выбор. - person Ian Boyd; 12.05.2017
comment
Почему в ваших ответах отсутствует Content-Length? - person Vinnie Falco; 09.01.2018
comment
@VinnieFalco Это ответ о коде ответа 201. Content-Length опущен для пояснительных целей. - person Ian Boyd; 11.01.2018

Я думаю, что atompub REST API - отличный пример спокойного сервиса. См. Приведенный ниже фрагмент из спецификации atompub:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

Сервер сигнализирует об успешном создании с кодом состояния 201. Ответ включает в себя заголовок Location, указывающий URI элемента-элемента для записи Atom, и представление этой записи в теле ответа.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

Запись, созданная и возвращенная коллекцией, может не совпадать с записью, отправленной клиентом. Сервер МОЖЕТ изменить значения различных элементов в записи, таких как значения atom: id, atom: updated и atom: author, и МОЖЕТ выбрать удаление или добавление других элементов и атрибутов или изменение содержимого элемента и значений атрибутов.

person Chandra Patni    schedule 27.12.2009
comment
Возврат созданного ресурса может быть немного большим, если размер ресурса составляет гигабайты ... - person Tor Valamo; 27.12.2009
comment
Согласовано! Это оптимизация по необходимости, но вы не хотите делать это преждевременно. Важно проектировать в Restful spirits и делать исключения только тогда, когда они необходимы. - person Chandra Patni; 27.12.2009
comment
@ChandraPatni, Атом мертв. Нужны примеры получше. - person Pacerier; 08.10.2015
comment
Атом может быть мертв, но дух примера все еще актуален. - person Ashimema; 27.10.2015
comment
В чем ключевое отличие этого ответа от ответа 200? Насколько я могу судить, отличия заключаются в самом коде состояния и включении заголовка Location. Похоже, что в основном 200 + вот URL-адрес на потом! . В этом суть? - person Anthony; 30.08.2016
comment
Моя первоначальная интерпретация ответа 201 была больше похожа на эй, вы хотели создать ресурс, но в зависимости от контекста вы либо не были заинтересованы в конечном результате, либо у вас есть доступ для записи, но нет доступа для чтения к этому ресурсу. В любом случае все, что вам нужно, прежде чем вернуться в основную коллекцию, - это URL-адрес созданного ресурса. В качестве доказательства это было создано. Все, что выходит за рамки этого, по сути, похоже на ответ 200. Если только RFC не имел в виду что-то еще. - person Anthony; 30.08.2016
comment
проголосовали за! если вы добавляете ресурс через PUT в базу данных, и если элемент не добавляется, потому что он уже существует, вы все равно возвращаете 201? - person PirateApp; 14.06.2020

В нескольких словах:

  • 200, когда объект создается и возвращается
  • 201, когда объект создается, но возвращается только его ссылка (например, идентификатор или ссылка)
person Stéphane Bruckert    schedule 06.06.2017
comment
Источник для этого? - person sudo soul; 23.10.2018
comment
Это то, что я понял из w3.org/Protocols/rfc2616/rfc2616-sec10.html и https://httpstatuses.com/201 - person Stéphane Bruckert; 24.10.2018
comment
После прочтения tools.ietf.org/html/rfc7231#section-6.3.1, я согласен с этим пониманием - я полагаю, я больше спрашивал, как вы к этому пришли. Но теперь, в моем понимании ... 200 = ресурс создан и возвращен | 201 = ресурс создан и возвращается ссылка | 204 = ресурс создан, полезная нагрузка не возвращена - person sudo soul; 24.10.2018
comment
@sudosoul Будет ли заголовок местоположения также возвращаться с 204, как в 201? - person Miguel Pynto; 15.09.2020
comment
@MiguelPynto Согласно RFC 7231, я бы сказал, что заголовок местоположения не должен возвращаться с 204. Хотя ответ 204 может включать метаданные заголовка, которые в конечном итоге подразумевают, что запрос был успешным. Проверьте ссылку, которую я опубликовал на RFC 7231, и посмотрите абзац о 204. - person sudo soul; 15.09.2020

Ознакомьтесь с HTTP: Определения методов: POST.

Действие, выполняемое методом POST, может не привести к ресурсу, который можно идентифицировать с помощью URI. В этом случае подходящим статусом ответа является либо 200 (ОК), либо 204 (Нет содержимого), в зависимости от того, включает ли ответ сущность, описывающую результат.

Если ресурс был создан на исходном сервере, ответ ДОЛЖЕН быть 201 (Создан) и содержать объект, который описывает статус запроса и относится к новому ресурсу, и заголовок Location (см. Раздел 14.30).

person ma11hew28    schedule 16.05.2014

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

Это просто пара "ключ-значение", разделенная двоеточиями.

ETag: "xyzzy"

Это могут быть текстовые данные любого типа - я обычно включаю строку JSON с идентификатором созданного элемента. Сама по себе простота тестирования делает его целесообразным.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

В этом примере идентификатор, uri и тип созданного элемента являются «характеристиками ресурса и местоположением».

person tempire    schedule 26.12.2009
comment
Вы говорите, что ETag соответствует объекту, содержащему список характеристик ресурса и местоположения. Я вижу, что ваше предложение хорошее, полностью согласен с вашей точкой зрения о тестировании. Однако я не понимаю, как это согласуется со списком характеристик и местоположений ресурсов. - person djna; 26.12.2009
comment
Список характеристик и местоположений ресурсов будет содержанием любой предоставленной структуры данных. Более строгая реализация могла бы включать в структуру JSON URI ресурса и, возможно, тип созданного ресурса. Я откорректирую ответ как таковой. - person tempire; 27.12.2009
comment
Укажите проблемы, чтобы люди могли узнать их. В противном случае комментарий просто машет рукой. - person tempire; 22.10.2013
comment
@SimonGibbs Какие проблемы? - person MEMark; 04.07.2014
comment
Хотя это строго соответствует спецификации, он рекомендует весьма необычный вариант реализации. Кроме того, он фактически не отвечает на вопрос вверху страницы (или делает это путем смешивания слов ETag и entity). Ответ с 43 голосами, вероятно, лучше. - person Simon Gibbs; 08.07.2014
comment
Использование ETag нарушает намерение, которое является альтернативой Last-Modified, т.е. обнаруживает, изменился ли ресурс. Если комментарий 1234 редактируется / обновляется, ваш etag остается неизменным, поэтому клиент не получит обновленную версию по запросу. - person nilskp; 21.11.2016
comment
В спецификации это намерение не указано; для чего нужна спецификация, если не для намерения? Может быть принято использовать его для Last-Modified, но спецификация гораздо более гибкая. - person tempire; 14.03.2017
comment
Хотя это общепринятый ответ, на самом деле он совершенно неверен. Это правильно, что вы МОЖЕТЕ использовать ETag для этой цели, но из-за ответа может показаться, что это общепринятый способ интерпретации стандарта, но это совсем не так. Например, вы можете просто вернуть URL-адрес - и это в заголовке Location даже указано в RFC как возможность, и он делает именно то, что указано в спецификации для объекта, содержащего список характеристик ресурсов и местоположений. - person nepdev; 21.06.2017
comment
Это не так. Возможно, это не обычное использование, но ошибочность означает, что спецификация должна явно указывать, для чего она должна использоваться. На самом деле вы имеете в виду, что я не использую его ни для чего, кроме x, поэтому вам тоже не следует этого делать. Если мы просто констатируем мнения как фактически верные, то я скажу, что ограничение использования только Last-Modified неверно. - person tempire; 24.06.2017
comment
RFC 7232 (один из нескольких, которые в совокупности устарел RFC 2616 - этот исходный вопрос и ответ довольно старый!) Вновь требует, чтобы значение ETag было непрозрачным идентификатором. То есть вы, как клиент, не должны пытаться интерпретировать его, просто повторно представьте его в более позднем запросе. - person jrg; 22.08.2017
comment
Включение статического (никогда не меняющегося) идентификатора в ETag может привести к непреднамеренному кэшированию ресурса. См. Ответ ниже stackoverflow.com/a/36373586/3622300 - person Guney Ozsan; 05.05.2020

Вывод фактически зависит от запрашиваемого типа содержимого. Однако, как минимум, вы должны поместить созданный ресурс в Location. Точно так же, как шаблон Post-Redirect-Get.

В моем случае я оставляю это поле пустым, пока не будет запрошено иное. Поскольку это поведение JAX-RS при использовании Response.created ().

Однако просто обратите внимание, что браузеры и фреймворки, такие как Angular, не следуют 201 автоматически. Я заметил поведение в http://www.trajano.net/2013/05/201-created-with-angular-resource/

person Archimedes Trajano    schedule 03.05.2013

Еще один ответ, который я хотел бы получить по этому поводу, - это использовать прагматичный подход и сохранить ваш REST Контракт API простой. В моем случае я реорганизовал свой REST API, чтобы сделать его более тестируемым, не прибегая к JavaScript или XHR, а только к простым HTML-формам и ссылкам.

Чтобы быть более конкретным по вашему вопросу выше, я бы просто использовал код возврата 200, а возвращаемое сообщение содержало сообщение JSON, которое ваше приложение может понять. В зависимости от ваших потребностей может потребоваться идентификатор вновь созданного объекта, чтобы веб-приложение могло получить данные в другом вызове.

Одно замечание: в моем отредактированном контракте API ответы POST не должны содержать никаких кэшируемых данных, поскольку POST на самом деле не кэшируются, поэтому ограничьте его идентификаторами, которые можно запросить и кэшировать с помощью запроса GET.

person Archimedes Trajano    schedule 23.07.2014