Код ответа HTTP для POST, когда ресурс уже существует - PullRequest
698 голосов
/ 30 сентября 2010

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

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

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

{json representation of the object}

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

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

POST /objects/ HTTP/1.1
...

{json representation of the object, including ID}

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

Ответы [ 14 ]

869 голосов
/ 30 сентября 2010

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

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

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

78 голосов
/ 09 ноября 2016

Согласно RFC 7231 , 303 МОЖЕТ быть использовано МОЖЕТ использоваться Если результат обработки POST будет эквивалентен представлению существующего ресурса .

71 голосов
/ 30 сентября 2010

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

Согласно RFC 4918

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

22 голосов
/ 25 декабря 2015

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

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

10.4.4 403 Запрещено

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

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

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

9,6 PUT

...

Принципиальная разница между запросами POST и PUT заключается в отражено в различном значении Request-URI. URI в POST-запрос идентифицирует ресурс, который будет обрабатывать вложенный юридическое лицо. Этот ресурс может быть процессом приема данных, шлюзом к какой-то другой протокол или отдельный объект, который принимает аннотации. В напротив, URI в запросе PUT идентифицирует объект, заключенный в запрос - пользовательский агент знает, для чего предназначен URI, и Сервер НЕ ДОЛЖЕН пытаться применить запрос к другому ресурсу. Если сервер желает, чтобы запрос был применен к другому URI,

он ДОЛЖЕН отправить ответ 301 (Постоянно перемещен); пользовательский агент МОЖЕТ затем принять собственное решение относительно того, следует ли перенаправить запрос.

13 голосов
/ 16 мая 2012

«302 найдено» звучит логично для меня. И RFC 2616 говорит, что на него МОЖНО ответить на другие запросы, кроме GET и HEAD (и это, безусловно, включает POST)

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

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

ОБНОВЛЕНИЕ: После перечитывания RFC я все еще думаю, что несуществующий код "4XX + 303 Found" должен быть правильным. Тем не менее, «Конфликт 409» является лучшим из существующих кодов ответов (как указано @ Wrikken), возможно, включая заголовок Location, указывающий на существующий ресурс.

10 голосов
/ 08 августа 2018

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

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

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

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

  • 200 OK
  • 201 Создан
  • ...

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

  • 302 Найдено
  • 303 См. Другие
  • ...

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

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

9 голосов
/ 30 сентября 2014

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

POST, как вы знаете, предназначен для изменения коллекции, и он используется для СОЗДАНИЯ нового элемента.Таким образом, если вы отправляете идентификатор (я думаю, что это не очень хорошая идея), вам следует изменить коллекцию, то есть изменить элемент, но это сбивает с толку.

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

Если вы хотите захватить УНИКАЛЬНОЕ ограничение (не идентификатор), вы можете ответить 409, как вы можете сделать в запросах PUT.Но не удостоверение личности.

6 голосов
/ 27 октября 2016

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

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

5 голосов
/ 07 апреля 2018

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

В качестве аргумента против других ответов использование любого не-1004 * кода ошибки подразумевает, что это не ошибка клиента, и это, очевидно, так. Использовать не-1005 * код ошибки для представления клиентской ошибки просто не имеет никакого смысла.

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

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

4 голосов
/ 18 марта 2016

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

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

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

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

Я полагаюсь на 202 и возвращаю содержимое, похожее на то, что вернул бы GET /{resource}/{id}.

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