400 против 422 ответа на POST данных

356

Я пытаюсь выяснить, какой правильный код состояния должен возвращаться в различных сценариях с помощью API-интерфейса типа REST, над которым я работаю. Допустим, у меня есть конечная точка, которая позволяет делать покупки POST в формате JSON. Это выглядит так:

{
    "account_number": 45645511,
    "upc": "00490000486",
    "price": 1.00,
    "tax": 0.08
}

Что я должен вернуть, если клиент отправляет мне «sales_tax» (вместо ожидаемого «налога»). В настоящее время я возвращаю 400. Но я начал сомневаться в этом. Должен ли я действительно возвращать 422? Я имею в виду, что это JSON (который поддерживается) и это действительный JSON, он просто не содержит всех обязательных полей.

Дэвид С
источник

Ответы:

419

400 Bad Request теперь может показаться лучшим кодом состояния HTTP / 1.1 для вашего варианта использования.

Во время вашего вопроса (и моего первоначального ответа) RFC 7231 не был чем-то особенным; в этот момент я возразил, 400 Bad Requestпотому что RFC 2616 сказал (с акцентом мой):

Сервер не может понять запрос из-за неправильного синтаксиса .

и запрос, который вы описываете, является синтаксически допустимым JSON, заключенным в синтаксически допустимый HTTP, и, следовательно, у сервера нет проблем с синтаксисом запроса.

Однако, как отметил Ли Саферит в комментариях , RFC 7231, который устарел RFC 2616, не включает это ограничение :

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


Однако до этой переписки (или если вы хотите поспорить о том, что RFC 7231 является только предлагаемым стандартом прямо сейчас), 422 Unprocessable Entityне кажется неправильным код состояния HTTP для вашего варианта использования, потому что во введении к RFC 4918 говорится:

Хотя коды состояния, предоставляемые HTTP / 1.1, достаточны для описания большинства состояний ошибок, с которыми сталкиваются методы WebDAV, есть некоторые ошибки, которые не попадают аккуратно в существующие категории. Эта спецификация определяет дополнительные коды состояния, разработанные для методов WebDAV (Раздел 11)

И описание422 говорит:

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

(Обратите внимание на ссылку на синтаксис; я подозреваю, что 7231 частично устарел и 4918)

Это звучит точно так же, как ваша ситуация, но на случай, если возникли какие-либо сомнения, он говорит:

Например, это условие ошибки может возникнуть, если тело запроса XML содержит правильно сформированные (то есть синтаксически правильные), но семантически ошибочные инструкции XML.

(Замените «XML» на «JSON», и я думаю, что мы можем согласиться, что это ваша ситуация)

Теперь некоторые будут возражать, что RFC 4918 относится к «HTTP-расширениям для Web-распределенной авторизации и управления версиями (WebDAV)» и что вы (предположительно) ничего не делаете с WebDAV, поэтому не должны использовать его.

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

Кроме того, в разделе 21.4 RFC 4918 содержится ссылка на реестр кодов состояния протокола IANA для передачи гипертекста (HTTP) , где можно найти 422.

Я предполагаю, что для клиента или сервера HTTP вполне разумно использовать любой код состояния из этого реестра, если они делают это правильно.


Но с HTTP / 1.1 у RFC 7231 есть тяга, так что просто используйте 400 Bad Request!

Кристиан Гласс
источник
5
Ваш ответ (422) имеет смысл для меня. Это также то, что использует Rails ( response_with ), когда ресурс не может быть обработан из-за ошибок валидации.
Тайлер Рик
11
Обратите внимание на использование 422 в спецификации, отличной от WebDAV, здесь: tools.ietf.org/html/rfc5789#section-2.2
Андрей Щекин
4
В качестве обновления RFC 7231 имеет другое описание для кода ответа 400, который изменяет семантику.
Ли Саферите
5
Мои извинения - я обновил этот ответ, чтобы отразить изменения в RFC и потерял некоторую ясность; Я постараюсь рефакторинг. Почти наверняка безопасно использовать 422, но в настоящее время вы должны использовать 400.
Кристиан Гласс
2
Я все еще думаю, что спецификация может быть намного яснее. Примеры, приведенные в, являются очевидными случаями, когда клиент делает что-то не так. Ситуация ОП также попадает в эту категорию. Однако бывают случаи, когда «я понимаю, о чем вы спрашиваете, но я отказываюсь делать это, потому что есть какое-то бизнес-правило против него», не так ясно. Это не совсем ошибка клиента, поэтому на самом деле может применяться 403 по той же спецификации: «Однако запрос может быть запрещен по причинам, не связанным с учетными данными». Я бы предпочел иметь отдельные коды для материалов, связанных с разрешениями, а не "это невозможно сделать".
Торарин
38

400 Bad Request - правильный код статуса HTTP для вашего варианта использования. Код определяется HTTP / 0.9-1.1 RFC.

Сервер не может понять запрос из-за неправильного синтаксиса. Клиент НЕ ДОЛЖЕН повторять запрос без изменений.

http://tools.ietf.org/html/rfc2616#section-10.4.1

422 Unprocessable Entity определяется RFC 4918 - WebDav. Обратите внимание, что есть небольшая разница по сравнению с 400, см. Цитируемый текст ниже.

Это условие ошибки может возникнуть, если тело XML-запроса содержит правильно сформированные (т. Е. Синтаксически правильные), но семантически ошибочные инструкции XML.

Чтобы сохранить единый интерфейс, вы должны использовать 422 только в случае ответов XML, а также поддерживать все коды состояния, определенные расширением Webdav, а не только 422.

http://tools.ietf.org/html/rfc4918#page-78

Смотрите также сообщение Марка Ноттингема о кодах статуса:

ошибочно пытаться отобразить каждую часть вашего приложения «глубоко» в коды состояния HTTP; в большинстве случаев уровень детализации, к которому вы хотите стремиться, гораздо грубее. В случае сомнений можно использовать универсальные коды состояния 200 OK, 400 Bad Request и 500 Internal Service Error, когда нет лучшего соответствия .

Как думать о кодах статуса HTTP

filip26
источник
4
Код 422 является частью реестра IANA iana.org/assignments/http-status-codes/http-status-codes.xhtml, поэтому любое IMHO не имеет смысла. В любом случае REST API Facebook и Twitter заново изобретают собственные коды и не используют стандарты RFC / IANA. Так что вы можете сделать.
gavenkoa
15
В разделе 11 конкретно говорится, что они добавляются ко всей спецификации, а не только в спецификации WebDav:The following status codes are added to those defined in HTTP/1.1 [RFC2616].
Стив Таубер,
8
Тот факт, что код описан как часть спецификации WebDAV, не означает, что он специфичен для WebDAV! Коды состояния должны быть общими.
хорошо относитесь к своим модам
33

Чтобы отразить статус на 2015 год:

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

Однако я ожидаю увидеть 400 используемых в настоящее время более широко, и, кроме того, пояснения, которые предоставляет спецификация HTTPbis, делают его более подходящим из двух кодов состояния:

  • Спецификация HTTPbis разъясняет намерение 400 не быть исключительно для синтаксических ошибок. Теперь используется более широкая фраза «указывает, что сервер не может или не будет обрабатывать запрос из-за чего-то, что воспринимается как ошибка клиента».
  • 422 Конкретно является расширением WebDAV и не упоминается в RFC 2616 или в более новой спецификации HTTPbis .

Для контекста, HTTPbis - это версия спецификации HTTP / 1.1, которая пытается прояснить области, которые неясны или противоречивы. Как только он достиг утвержденного статуса, он заменит RFC2616.

Том Кристи
источник
4
Разве 403 Forbidden также не может быть использован для этого контекста? Цитата: Код состояния 403 (Запрещено) указывает, что сервер понял запрос, но отказывается его авторизовать ... Если в запросе были предоставлены учетные данные аутентификации, сервер считает их недостаточными для предоставления доступа .... Однако запрос может быть запрещенным по причинам, не связанным с полномочиями. Таким образом, похоже, что 403 может использоваться для отклонения запросов вне аутентификации.
сборщик мусора
1
@garbagecollector обратите внимание, что «отклонено по причинам вне учетных данных »! = «отклонено по причинам вне проверки подлинности ». Существует множество способов аутентификации кого-либо без использования учетных данных.
Кнетик
@garbagecollector no, учетные данные означают аутентификацию («кто ты»), которая в случае сбоя будет 401. Авторизация («что вы можете сделать») будет 403 при неудаче. Полное объяснение здесь: stackoverflow.com/a/6937030/137948 Ни то, ни другое не применимо к ситуации с «пропущенными полями» ОП, поскольку ошибка будет одинаковой независимо от того, какой пользователь попытался ее исправить. Я согласен, 400 является правильным ответом.
Уилл Шеппард
27

Пример использования GitHub API

https://developer.github.com/v3/#client-errors

Возможно, копирование из хорошо известных API - это разумная идея:

Существует три возможных типа ошибок клиента при вызовах API, которые получают тела запросов:

Отправка неверного JSON приведет к ответу 400 Bad Request.

HTTP/1.1 400 Bad Request
Content-Length: 35

{"message":"Problems parsing JSON"}

Отправка неправильного типа значений JSON приведет к ответу 400 Bad Request.

HTTP/1.1 400 Bad Request
Content-Length: 40

{"message":"Body should be a JSON object"}

Отправка неверных полей приведет к ответу 422 Unprocessable Entity.

HTTP/1.1 422 Unprocessable Entity
Content-Length: 149

{
  "message": "Validation Failed",
  "errors": [
    {
      "resource": "Issue",
      "field": "title",
      "code": "missing_field"
    }
  ]
}
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
источник
Я думаю, что это правильный и понятный ответ.
LEMUEL ADANE
1
Не могу больше проголосовать. Хотелось бы, чтобы больше проголосовавших ответов относились к этому. Спецификации (RFC, IANA) эпически не смогли дать четких определений и различий между ними. Таким образом, ответ сводится к лучшим практикам, и GitHub дает нам один.
Алекс Клаус
15

Правильного ответа нет, поскольку это зависит от того, какое определение «синтаксис» используется для вашего запроса. Самое главное, что вы:

  1. Используйте код (ы) ответа последовательно
  2. Включите как можно больше дополнительной информации в тело ответа, чтобы помочь разработчикам, использующим ваш API, понять, что происходит. =

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

В этом конкретном примере вопрос OP касается запроса JSON, который содержит ключ, отличный от ожидаемого. Теперь полученное имя ключа очень похоже, с точки зрения естественного языка, на ожидаемый ключ, но оно строго отличается и, следовательно, не распознается (обычно) машиной как эквивалентное.

Как я уже говорил выше, решающим фактором является то, что подразумевается под синтаксисом . Если запрос был отправлен с типом содержимого application/json, то да, запрос синтаксически действителен, потому что это допустимый синтаксис JSON, но не семантически действителен, поскольку он не соответствует ожидаемому. (при условии строгого определения того, что делает рассматриваемый запрос семантически действительным или нет).

С другой стороны, если запрос был отправлен с более конкретным пользовательским типом контента application/vnd.mycorp.mydatatype+json, например, он точно указывает, какие поля ожидаются, то я бы сказал, что запрос может быть легко синтаксически недействительным, следовательно, ответ 400.

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

cdeszaq
источник
Очень недооцененный ответ - спасибо за хорошо сформулированное объяснение.
puiu
Именно мои мысли по этому вопросу! Я исхожу из истории XML SOAP и концепции схемы, которая только что попала в мою кровь, а документы JSON, скорее, не объявляют свою схему. Для меня это вопрос, понимает ли сервер запрос или нет. Если сервер не знает, что такое «sales_tax», тогда просто 400: «Я понятия не имею, что вы мне отправили, но определенно не то, что я хочу».
Александр Стельмачонек,
4

Объяснение 422 необработанного объекта Обновлено: 6 марта 2017 г.

Что такое 422 необработанный объект?

Код состояния 422 возникает, когда запрос правильно сформирован, однако из-за семантических ошибок он не может быть обработан. Этот статус HTTP был введен в RFC 4918 и более конкретно ориентирован на расширения HTTP для Web Distributed Authoring and Versioning (WebDAV).

Существует некоторое противоречие относительно того, должны ли разработчики возвращать клиентам ошибку 400 против 422 (подробнее о различиях между обоими статусами ниже). Однако в большинстве случаев считается, что статус 422 следует возвращать только в том случае, если вы поддерживаете возможности WebDAV.

Дословное определение кода состояния 422, взятого из раздела 11.2 в RFC 4918, можно прочитать ниже.

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

Определение продолжает говорить:

Например, это условие ошибки может возникнуть, если тело запроса XML содержит правильно сформированные (то есть синтаксически правильные), но семантически ошибочные инструкции XML.

400 против 422 кодов состояния

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

Использование статуса 422 должно быть зарезервировано только для очень конкретных случаев использования. В большинстве других случаев, когда произошла ошибка клиента из-за неправильного синтаксиса, следует использовать статус 400 Bad Request.

https://www.keycdn.com/support/422-unprocessable-entity/

Clojurevangelist
источник
1

Ваш случай: HTTP 400 это правильный код состояния для вашего случая с точки зрения REST, поскольку его синтаксически неверно отправлять sales_taxвместо tax, хотя это допустимый JSON. Обычно это применяется большинством серверных структур при отображении JSON в объекты. Однако есть некоторые реализации REST, которые игнорируют новое keyв объекте JSON. В этом случае пользовательская content-typeспецификация для принятия только допустимых полей может быть применена на стороне сервера.

Идеальный сценарий для 422:

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

Ситуации 400 на 422:

Помните, что код ответа 422 - это расширенный код состояния HTTP (WebDAV). Есть еще некоторые HTTP-клиенты / интерфейсные библиотеки, которые не готовы обрабатывать 422. Для них это так же просто, как «HTTP 422 неверен, потому что это не HTTP» . С точки зрения сервиса, 400 не совсем конкретен.

В корпоративной архитектуре сервисы развертываются в основном на сервисных уровнях, таких как SOA, IDM и т. Д. Они обычно обслуживают несколько клиентов, начиная от очень старого собственного клиента и заканчивая новейшими клиентами HTTP. Если один из клиентов не обрабатывает HTTP 422, возможны варианты, когда клиент просит обновить или изменить код ответа на HTTP 400 для всех. По моему опыту, это очень редко в наши дни, но все еще возможность. Поэтому перед принятием решения о кодах ответа HTTP всегда требуется тщательное изучение вашей архитектуры.

Чтобы справиться с подобной ситуацией, сервисные уровни обычно используют versioningили устанавливают configurationфлаг для клиентов строгого соответствия HTTP для отправки 400 и отправки 422 для остальных из них. Таким образом, они обеспечивают поддержку обратной совместимости для существующих потребителей, но в то же время предоставляют возможность новым клиентам использовать HTTP 422.


Последнее обновление RFC7321 гласит:

The 400 (Bad Request) status code indicates that the server cannot or
   will not process the request due to something that is perceived to be
   a client error (e.g., malformed request syntax, invalid request
   message framing, or deceptive request routing).

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

Yuvi
источник
1

Во-первых, это очень хороший вопрос.

400 Bad Request - когда в запросе отсутствует важная часть информации

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

422 Unprocessable Entity - когда тело запроса не может быть проанализировано.

Это менее серьезно, чем 400. Запрос достиг сервера. Сервер подтвердил, что запрос имеет правильную базовую структуру. Но информация в теле запроса не может быть проанализирована или понята.

например, Content-Type: application/xmlкогда тело запроса - JSON.

Вот статья, в которой перечислены коды состояния и их использование в REST API. https://metamug.com/article/status-codes-for-rest-api.php


источник
5
422 означает, что синтаксис действителен, а содержание - нет. Отправка JSON в том месте, где ожидается XML, означает, что синтаксис неправильный, поэтому 400 - правильный ответ в этом случае.
Дирк
1
Точно так же, как сказал Дирк, 422 означает синтаксически правильный запрос (может быть проанализирован и понят), но семантически неверный
Яцек Обарымский
400: когда запрос не может быть обработан из-за неверного синтаксиса (например, ошибка синтаксического анализа); 422: когда запрос не может быть обработан из-за неверных данных (например, ошибка проверки).
Китанотори
Ваш пример для 422 недопустим, потому что при отправке json с типом носителя application / xml тело автоматически становится синтаксически неправильным, и ответ должен быть 400.
manemarron
-15

На самом деле вы должны вернуть «200 OK» и в теле ответа включить сообщение о том, что произошло с опубликованными данными. Тогда ваше приложение должно понять сообщение.

Дело в том, что коды состояния HTTP - это именно так - коды состояния HTTP. И они должны иметь значение только на транспортном уровне, а не на прикладном уровне. Прикладной уровень действительно никогда не должен знать, что используется HTTP. Если вы переключили свой транспортный уровень с HTTP на Homing Pigeons, это никак не должно повлиять на уровень вашего приложения.

Позвольте мне привести не виртуальный пример. Допустим, вы влюбились в девушку, и она любит вас обратно, но ее семья переезжает в совершенно другую страну. Она дает вам свой новый почтовый адрес. Естественно, вы решили отправить ей любовное письмо. Итак, вы пишете свое письмо, кладете его в конверт, пишете ее адрес на конверте, ставите на нем штамп и отправляете его. Теперь давайте рассмотрим эти сценарии

  1. Вы забыли написать название улицы. Вы получите неоткрытое письмо обратно с сообщением, в котором говорится, что адрес неверен. Вы испортили запрос, и получающее почтовое отделение не может обработать его. Это эквивалентно получению «400 Bad Request».
  2. Таким образом, вы исправляете адрес и отправляете письмо снова. Но из-за какой-то неудачи вы совершенно неправильно написали название улицы. Вы получите письмо обратно с сообщением, что адрес не существует. Это эквивалентно получению «404 Not Found».
  3. Вы снова фиксируете адрес, и на этот раз вам удается правильно написать адрес. Ваша девушка получает письмо и пишет вам обратно. Это эквивалентно получению «200 ОК». Однако это не значит, что вам понравится то, что она написала в своем письме. Это просто означает, что она получила ваше сообщение и ответила вам. Пока вы не откроете конверт и не прочитаете ее письмо, вы не сможете понять, очень ли она скучает по вам или хочет порвать с вами.

Короче говоря, возвращение «200 OK» не означает, что у серверного приложения есть хорошие новости для вас. Это только означает, что у него есть новости.

PS: код состояния 422 имеет значение только в контексте WebDAV. Если вы не работаете с WebDAV, то 422 имеет то же самое стандартное значение, что и любой другой нестандартный код = которого нет.

GoFree
источник