Код ответа HTTP для POST, когда ресурс уже существует

Я создаю сервер, который позволяет клиентам сохранять объекты. Эти объекты полностью построены на стороне клиента, в комплекте с идентификаторами объектов, которые являются постоянными в течение всего срока службы объекта.

Я определил API, чтобы клиенты могли создавать или изменять объекты с помощью PUT:

PUT /objects/{id} HTTP/1.1
...

{json representation of the object}

{id} - это идентификатор объекта, поэтому он является частью запроса-URI.

теперь я также рассматриваю возможность разрешить клиентам создавать объект с помощью Сообщение:

POST /objects/ HTTP/1.1
...

{json representation of the object, including ID}

поскольку POST подразумевается как операция "добавить", я не уверен, что делать, если объект уже есть. Должен ли я рассматривать запрос как запрос на изменение или должен вернуть некоторый код ошибки (который)?

15 ответов


Мне кажется 409 Conflict является наиболее подходящим, однако, редко встречается в дикой природе:

запрос не может быть завершена из-за конфликта с текущим состоянием ресурса. Этот код разрешен только в ситуациях, когда ожидается, что пользователь сможет разрешить конфликт и повторно отправить запрос. Орган реагирования должен включать достаточно информации, чтобы пользователь мог распознать источник конфликта. В идеале, объект response будет включать достаточно информации для пользователя или агента пользователя, чтобы устранить проблему; однако это может быть невозможно и не требуется.

конфликты, скорее всего, возникнут в ответ на запрос PUT. Например, если используется управление версиями и объект, который помещается, включает изменения в ресурс, которые противоречат тем, которые были сделаны более ранним (сторонним) запросом, сервер может использовать ответ 409, чтобы указать, что он не может выполнить запрос. В этом случае объект ответа, скорее всего, будет содержать список различий между двумя версиями в формате, определенном типом содержимого ответа.


лично я иду с расширением WebDAV 422 Unprocessable Entity.

Rest Patterns описывает его как

на 422 Unprocessable Entity код состояния означает, что сервер понимает тип содержимого сущности запроса (следовательно,415 Unsupported Media Type код состояния неуместен), и синтаксис сущности запроса правильный (таким образом,400 Bad Request код состояния неуместен), но не удалось обработать содержащиеся инструкции.


по данным RFC 7231, a 303 См. Другие можно использовать если результат обработки поста будет эквивалентен представление существующего ресурса.


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

чтобы немного расширить ответ Wrikken, я думаю, вы могли бы использовать либо 409 Conflict или 403 Forbidden в зависимости от ситуации-короче говоря, используйте ошибку 403, когда пользователь не может ничего сделать для разрешения конфликта и завершения запроса (например, они не могут отправить DELETE запрос на явное удаление ресурса), или используйте 409, если что-то может быть сделанный.

10.4.4 403 запрещено

сервер понял запрос, но отказывается выполнять его. Разрешение не поможет, и запрос не должен повторяться. Если метод запроса не был HEAD, и сервер хочет сделать общедоступным почему запрос не был выполнен, в нем должна быть описана причина за отказ в сущности. Если сервер не желает делать эта информация доступна клиенту, код состояния 404 (не Найдено) можно использовать вместо этого.

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

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

9.6 поставить

...

принципиальная разница между запросами POST и PUT заключается в отражается в различном значении запроса-URI. URI в a POST-запрос определяет ресурс, который будет обрабатывать вложенный сущность. Этот ресурс может быть процессом приема данных, шлюзом для какой-то другой протокол или отдельный объект, который принимает аннотации. В напротив, URI в запросе PUT идентифицирует сущность, заключенную в запрос -- агент пользователя знает, что URI предназначен и сервер не должен пытаться применить запрос к какому-либо другому ресурсу. Если сервер желает, чтобы запрос был применен к другому URI,

он должен отправить 301 (перемещенный постоянно) ответ; агент пользователя может затем принять собственное решение относительно того, следует ли перенаправлять запрос.


Как насчет возвращения 418?

поскольку клиент просит сохранить сущность, которая уже существует на сервере, сервер, наконец, злится и думает, что он чайник и возвращает:418 I'm a teapot.

ссылки:


" 302 найдено " звучит логично для меня. И RFC 2616 говорит, что на него можно ответить для других запросов, кроме GET и HEAD (и это, безусловно, включает POST)

но он по-прежнему держит посетителя на этот URL, чтобы получить этот "найденный" ресурс, RFC. Чтобы заставить его перейти непосредственно к реальному "найденному" URL-адресу, нужно использовать "303 See Other", что имеет смысл, но заставляет другой вызов получить следующий URL-адрес. С хорошей стороны, это GET кэшируемый.

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

обновление: после перечитывания RFC, я все еще думаю, что не существует "4xx+303 найдено" код должен быть правильным. Однако "409 конфликт" является лучшим существующим кодом ответа (как указано @ Wrikken), возможно, включая Заголовок местоположения, указывающий на существующий ресурс.


Я не думаю, что вы должны сделать это.

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

используйте его для добавления элемента без идентификатора. Это лучшая практика.

Если вы хотите захватить уникальное ограничение (не id), вы можете ответить 409, как вы можете сделать в запросах PUT. Но не ИДЕНТИФИКАТОР.


зачем 202 принято? Это запрос OK (200s), не было никаких ошибок клиента (400s), как таковых.

С 10 Определений Кода Состояния:

"202 принято. Запрос был принят для обработки, но обработка не была завершена."

... потому что ее не нужно было завершать, потому что она уже существовала. Клиент не знает о его существовании, он ничего не сделал. неправильный.

Я опираюсь на бросок 202 и возвращаю аналогичный контент в what a GET /{resource}/{id} вернули бы.


Я думаю, что для отдыха вам просто нужно принять решение о поведении для этой конкретной системы, и в этом случае, я думаю, что "правильный" ответ будет одним из пары ответов, приведенных здесь. Если вы хотите, чтобы запрос остановился и вел себя так, как будто клиент совершил ошибку, которую он должен исправить, прежде чем продолжить, используйте 409. Если конфликт действительно не так важен и вы хотите сохранить запрос, ответьте, перенаправив клиента на найденную сущность. Я думаю, что правильный REST APIs должно быть перенаправление (или, по крайней мере, предоставление заголовка местоположения) в конечную точку GET для этого ресурса после публикации, Так что это поведение даст согласованный опыт.

изменить: Также стоит отметить, что вы должны рассмотреть PUT, так как вы предоставляете идентификатор. Тогда поведение просто: "мне все равно, что там сейчас, положите эту вещь туда.- Это значит, что если там ничего нет, оно будет создано; если там что-то есть, оно будет заменено. Я думаю, что сообщение больше подходит, когда сервер управляет этим ID. Разделение двух концепций в основном говорит вам, как с этим бороться (т. е. PUT является идемпотентным, поэтому он всегда должен работать до тех пор, пока полезная нагрузка проверяет, POST всегда создает, поэтому, если есть столкновение идентификаторов, то 409 будет описывать этот конфликт).


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

патч решит проблему, позволяя вам обновлять уже существующие элементы. См.: RFC 5789: PATCH


Я бы пошел с 422 Unprocessable Entity, который используется, когда запрос недействителен, но проблема не в синтаксисе или аутентификации.

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

кажется,409 Conflict является наиболее распространенным ответом здесь, но, согласно спецификации, это означает, что ресурс уже существует, и новые данные, которые вы применяете к нему, несовместимы с его текущим состоянием. Если вы посылаете POST запрос, например, имя пользователя, которое уже занято, на самом деле не конфликтует с целевым ресурсом, поскольку целевой ресурс еще не был опубликован. Это ошибка специально для управления версиями, когда существует конфликт между версией сохраненного ресурса и версией запрошенного ресурса. Это очень полезно для этой цели, для пример, когда клиент кэширует старую версию ресурса и отправляет запрос на основе этой неправильной версии, которая больше не будет условно допустимой. "В этом случае представление ответа, вероятно, будет содержать информацию, полезную для объединения различий на основе истории изменений."Запрос на создание другого пользователя с этим именем пользователя просто необработан, не имея ничего общего с контролем версий.

для записи, 422 статус кода GitHub используется при попытке создать репозиторий с уже используемым именем.


насчет 208 - http://httpstatusdogs.com/208-already-reported ? Это вариант?

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


наткнулся на этот вопрос, проверяя правильный код для повторяющейся записи.

простите мое невежество, но я не понимаю, почему все игнорируют код "300", который ясно говорит" множественный выбор "или"неоднозначный"

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

https://tools.ietf.org/html/rfc7231#section-6.4.1


скорее это 400 Bad Request

6.5.1. 400 Плохой Запрос


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

поскольку запрос содержит повторяющееся значение(value что уже существует), то это может быть воспринято как ошибка клиента. Нужно изменить запрос перед следующей попыткой.
Рассматривая эти факты, мы можем заключить, что HTTP STATUS 400 плохой запрос.


Это все контекст, а также кто несет ответственность за наличие дубликатов (сервер или клиент или оба)

Если сервер просто точка дубликат, посмотрите на 4xx:

  • 400 Bad Request - когда сервер не будет обрабатывать запрос, потому что это очевидная ошибка клиента
  • 409 конфликт - если сервер не будет обрабатывать запрос, но причина этого не является ошибкой клиента

для подразумевается обработка дубликатов, посмотрите на 2XX:

  • 200 OK
  • 201 создан

если сервер ожидалось что-то вернуть, посмотрите на 3XX:

  • 302 нашел
  • 303 См. Другие

когда сервер может указывать существующий ресурс, подразумевает перенаправление.

Если выше недостаточно, это всегда хорошая практика подготовить сообщение об ошибке в теле ответа.