REST HTTP коды состояния для неудачной проверки или неверного дубликата

827

Я создаю приложение с API на основе REST и дошел до того, что я задаю коды состояния для каждого запроса.

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

Я просмотрел http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html, но ни один из них не кажется правильным.

Есть ли распространенная практика при отправке кодов состояния?

AlexN
источник
14
Откройте httpstatus.es , щелкните правой кнопкой мыши >> Закладка: P
Салман фон Аббас

Ответы:

781

Для ошибки проверки ввода: 400 Bad Request + ваше необязательное описание. Это предлагается в книге " RESTful Web Services ". Для двойной подачи: 409 конфликтов


Обновление июнь 2014

Соответствующей спецификацией был RFC2616 , который давал использование 400 (Bad Request) довольно узко

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

Таким образом, можно утверждать, что это неуместно для семантических ошибок. Но не больше; с июня 2014 года соответствующий стандарт RFC 7231 , который заменяет предыдущий RFC2616, дает более широкое использование 400 (Bad Request) как

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

Deamon
источник
3
Да, тело запроса является частью синтаксиса.
Деймон
62
Плохой запрос, безусловно, является наиболее распространенным ответом на этот вид проблемы. Единственная другая альтернатива - 422 Unprocessable Entity. Он на самом деле исходит от WebDav, но он вполне допустим для повторного использования любого кода состояния, который был зарегистрирован в IANA.
Даррел Миллер
19
Итак, как вы различаете искаженные данные, которые сервер даже не может проанализировать, и ошибку проверки? Клиент будет обрабатывать эти два ответа совершенно по-разному. Для проверки они, скорее всего, отобразят ошибки пользователю. Для действительно «искаженных данных» они регистрируют ошибку, поэтому ошибка в методе, который генерирует запрос, может быть исправлена.
Джош Но
18
Я не согласен с вашей интерпретацией RFC7231, хотя в ней говорится something perceived to be a client error, что все примеры, приведенные в этом параграфе, являются нарушениями протокола HTTP, а не логическими ошибками: синтаксис, кадрирование, маршрутизация. Таким образом, я считаю, что спецификация HTTP не позволяет 400 для неудачной проверки на уровне приложения.
Дима Тиснек
2
почему бы не использовать 422 - необработанный объект? Мне кажется более логичным
java_geek
278
  • Ошибка проверки: 403 Запрещено («Сервер понял запрос, но отказывается его выполнить»). Вопреки распространенному мнению, RFC2616 не говорит «403 предназначен только для неудачной аутентификации», но «403: я знаю, что вы хотите, но я не буду этого делать». Это условие может или не может быть связано с аутентификацией.
  • Попытка добавить дубликат: 409 Конфликт («Запрос не может быть выполнен из-за конфликта с текущим состоянием ресурса.»)

Вы должны определенно дать более подробное объяснение в заголовках и / или теле ответа (например, с пользовательским заголовком - X-Status-Reason: Validation failed).

Писквор покинул здание
источник
17
@deamon: Это не спецификация, это Википедия, то есть чье-то мнение о том, «что означают коды статуса HTTP»; обратите внимание, что на странице обязательно говорится «это то, что Apache означает с 403, это то, что IIS означает с 403», и нигде не ссылается на официальный RFC. Вы, кажется, повторяете «403 означает то, что говорит Apache». НЕ. Фактический RFC (который является соответствующим документом, а не реализацией Apache, не реализацией IIS, не реализацией кого-либо еще) находится здесь: w3.org/Protocols/rfc2616/rfc2616-sec10.html
Писквор покинул здание
57
«10.4.4 403 Запрещено Сервер понял запрос, но отказывается его выполнить. Авторизация не поможет, и запрос НЕ ДОЛЖЕН повторяться. Если метод запроса не был ГОЛОВНЫМ, и сервер желает сообщить, почему запрос не был выполнено, СЛЕДУЕТ описать причину отказа в объекте. Если сервер не желает предоставлять эту информацию клиенту, вместо этого можно использовать код состояния 404 (не найден). " Здесь я не вижу акцента («СЛЕДУЕТ / НЕ СЛЕДУЕТ» - это ключевые слова RFC 2119, а не акцент); это ваша идея, что означает «запрещено», а не RFC.
Писквор покинул здание
10
Мне нравится этот ответ, но все еще вижу одну маленькую проблему. Согласно спецификации , когда возвращается 403 , «запрос НЕ ДОЛЖЕН повторяться». Однако возврат 409 «разрешен только в ситуациях, когда ожидается, что пользователь сможет разрешить конфликт и повторно отправить запрос». В случае дубликата, я думаю, что 403 является более подходящим, поскольку вы не можете действительно разрешить конфликт (кроме как путем удаления предыдущего экземпляра ресурса).
Паблобм
2
Для самого сообщения об ошибке вы должны изменить фразу причины, поэтому отправка заголовка HTTP/1.0 403 Form validation errors- самый чистый путь.
апреля
6
ИМО, 422 «Необработанный объект» имеет гораздо больше смысла. Я рассуждаю не о том, что сервер отказывается выполнять запрос, а о том, что сервер не может выполнить запрос.
tybro0103
225

Я рекомендую код состояния 422 «Необработанный объект» .

11.2. 422 необработанного объекта

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

Джулиан Решке
источник
11
Конечно, это код состояния HTTP, см. Iana.org/assignments/http-status-codes . Есть больше кодов состояния, чем определено в RFC 2616.
Джулиан Решке
7
WebDAV - это расширение HTTP . «HTTP-расширения для веб-распределенной авторизации и управления версиями (WebDAV)» Итак, код состояния 422 - это не код состояния http, а код состояния исключений http.
Деймон
16
Дэймон, это не имеет смысла. HTTP определяет, как определять новые коды, и это то, что делает WebDAV. Там есть регистр кода состояния по причине.
Джулиан Решке
14
К вашему сведению - RFC описание 422: 11.2. 422 Unprocessable Entity Код состояния 422 (Unprocessable Entity) означает, что сервер понимает тип содержимого объекта запроса (следовательно, код состояния 415 (Unsupported Media Type) является неподходящим), и синтаксис объекта запроса является правильным (таким образом, 400 (Неправильный запрос) код состояния не подходит), но не удалось обработать содержащиеся в нем инструкции. Например, это условие ошибки может возникнуть, если тело запроса XML содержит правильно сформированные (то есть синтаксически правильные), но семантически ошибочные инструкции XML.
Стив Каллестад
6
И темы не истекают. Они должны остаться в живых, или лучшие результаты поиска Google начинают становиться неточными.
Джеймс Биллингем
81

200,300, 400, 500 очень общие. Если вы хотите универсальный, 400 в порядке.

422 используется все большим количеством API, и даже используется Rails из коробки.

Независимо от того, какой код статуса вы выбираете для своего API, кто-то не согласится. Но я предпочитаю 422, потому что считаю «400 + текстовый статус» слишком общим. Кроме того, вы не используете JSON-готовый парсер; Напротив, 422 с ответом JSON очень явный, и может быть передано много информации об ошибках.

Говоря об ответе JSON, я склонен стандартизировать ответ об ошибках Rails для этого случая, а именно:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

Этот формат идеально подходит для проверки формы, которую я считаю наиболее сложным вариантом для поддержки с точки зрения «богатства отчетов об ошибках». Если ваша структура ошибок такова, она, вероятно, будет обрабатывать все ваши потребности в сообщениях об ошибках.

sethcall
источник
2
Как насчет ошибок, возникающих в результате взаимодействия между аргументами. Это значит, что arg1он действителен и arg2действителен, но комбинация двух с конкретными отправленными значениями недопустима.
Иона
1
Я не переоценил бы это; просто выберите тот, который, кажется, владеет отношениями.
sethcall
или даже просто ошибка на обоих аргументах. Как пользователь, я думаю, я хотел бы видеть ошибку в каждом из полей, которые конфликтуют, я думаю.
прижимается
Ницца!. явное лучше, чем неявное
bhathiya-perera
46

200

Тьфу ... (309, 400, 403, 409, 415, 422) ... множество ответов, пытающихся угадать, спорить и стандартизировать, какой код возврата является лучшим для успешного HTTP-запроса, но неудачного вызова REST .

Это неправильно смешивать HTTP коды статуса и коды состояния покоя.

Однако я видел много реализаций, смешивающих их, и многие разработчики могут не согласиться со мной.

Коды возврата HTTP связаны с HTTP Requestсамим собой. Вызов REST выполняется с использованием запроса протокола передачи гипертекста, и он работает на более низком уровне, чем сам вызванный метод REST. REST - это концепция / подход, а его вывод - бизнес / логический результат, а код результата HTTP - транспорт .

Например, возвращение «404 Не найдено» при вызове / users / вызывает путаницу, поскольку это может означать:

  • Неверный URI (HTTP)
  • Пользователи не найдены (REST)

«403 Запрещено / Доступ запрещен» может означать:

  • Требуется специальное разрешение. Браузеры могут справиться с этим, спросив пользователя / пароль. (HTTP),
  • Неправильные разрешения доступа настроены на сервере. (HTTP),
  • Вам необходимо пройти проверку подлинности (REST)

И этот список может продолжаться с «500 Server error» (ошибка в HTTP-запросе Apache / Nginx или ошибка бизнес-ограничения в REST) ​​или другими ошибками HTTP и т. Д.

Из кода трудно понять, что было причиной сбоя, HTTP (транспортный) сбой или REST (логический) сбой.

Если HTTP-запрос физически выполнен успешно, он всегда должен возвращать 200 кодов, независимо от того, найдены записи или нет. Потому что ресурс URI найден и обработан сервером HTTP. Да, он может вернуть пустой набор. Можно ли получить пустую веб-страницу с 200 как результат HTTP, верно?

Вместо этого вы можете вернуть 200 HTTP-код с некоторыми опциями:

  • «ошибка» объекта в JSON, если что-то пойдет не так
  • Пустой массив / объект JSON, если запись не найдена
  • Флаг результата / успеха bool в сочетании с предыдущими опциями для лучшей обработки.

Кроме того, некоторые интернет-провайдеры могут перехватить ваши запросы и вернуть вам код HTTP 404. Это не означает, что ваши данные не найдены, но что-то не так на транспортном уровне.

Из вики :

В июле 2004 года британский телекоммуникационный провайдер BT Group развернул систему блокировки контента Cleanfeed, которая возвращает ошибку 404 при любом запросе контента, который, по мнению Internet Watch Foundation, считается потенциально незаконным. Другие Интернет-провайдеры возвращают ошибку HTTP 403 «Запрещено» при тех же обстоятельствах. Практика использования фальшивых ошибок 404 в качестве средства сокрытия цензуры была также отмечена в Таиланде и Тунисе. В Тунисе, где цензура была жестокой до революции 2011 года, люди узнали о природе фальшивых ошибок 404 и создали воображаемого персонажа по имени «Аммар 404», который представляет «невидимого цензора».

Почему бы просто не ответить чем-то вроде этого?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

Google всегда возвращает 200 в качестве кода состояния в своем API геокодирования, даже если запрос логически не выполняется: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook всегда возвращает 200 для успешных HTTP-запросов, даже если REST-запрос не выполняется: https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

Все просто, коды состояния HTTP предназначены для запросов HTTP. REST API - это Ваш, определите Ваши коды статуса.

Marcodor
источник
3
На самом деле, использование кодов состояния HTTP для REST еще более запутанно: 1) вы видите 4xx в наборе инструментов вашего разработчика, и вы не можете просто определить, возвратил ли сервер какое-либо разумное значение или не обработал ваш запрос вообще. а затем 2) все ваши обработчики ошибок / исключений / перехватчиков должны проверять, какой сервер возвращен в качестве ответа (в основном это не так, поскольку вам придется делать это при каждом вызове службы), и много раз 3) вы получаете одинаковую полезную нагрузку ( типа) как на пути успеха, так и на пути к ошибке, приводящей к сложному / дублированному коду ... Действительно, очень запутанно.
szczepanpp
9
Этот ответ путает оригинальную семантику протокола HTTP с тем, как REST через HTTP как архитектурный стиль переопределяет HTTP для реализации API веб-служб. Как архитектурный стиль, REST - это не стандарт, которому нужно строго следовать, а предлагаемый подход. Использование ответа 200 для ошибки проверки не является правильным или неправильным, однако вашим клиентам непонятно, что запрос выполнен успешно, но на самом деле произошел сбой из-за ошибки проверки, что является важной деталью, скрытой в теле ответа, семантика, которую клиент должен разобрать, чтобы понять.
Кевин Хук
5
@Marcodor, если ваш вызов API не удался, но вы возвращаете 200, указывающих на успех, как это хорошая идея? это непонятно и запутанно для потребителей вашего API.
Кевин Хук
3
Исправьте по многим причинам, а не только по разделению ошибок HTTP и REST. Проверка REST часто требует большего количества нюансов. Например, запись принята, но помечена как дубликат или отклонена для уникального нарушения индекса. Вы также хотите последовательную модель возврата. Метод .NET BadRequest()имеет свою собственную модель возврата, которая будет отличаться от вашей обычной модели возврата. Это кошмар, чтобы разобрать. @KevinHooke, возвращать HTTP 200 для ошибки проверки REST - все равно что сказать: «Я получил ваше сообщение, ответ - нет, и вот почему». Возвращение HTTP 400 говорит: «Я не знаю, о чем ты говоришь».
Нил Ласлетт
5
аргумент «потому что это делает Google, должно быть, правильно», для меня это безумие… можно бросить вызов тому, что Google реализовал детям. Возврат HTTP 200 для неудачного вызова rest сбивает с толку вызывающего API, это должно быть 4xx, и можно включить в тело красивый JSON / XML ... давайте вместе остановим безумие.
Джерил Кук,
43

Дубликат в базе данных должен быть 409 CONFLICT.

Я рекомендую использовать 422 UNPROCESSABLE ENTITYдля проверки ошибок.

Я дам более подробное объяснение кодов 4xx здесь .

Фил Паркер
источник
6

Код состояния 304 «Не изменен» также дает приемлемый ответ на дубликат запроса. Это похоже на обработку заголовка с If-None-Matchиспользованием тега объекта.

По моему мнению, ответ @ Piskvor - более очевидный выбор того, что, по моему мнению, является целью первоначального вопроса, но у меня есть альтернатива, которая также актуальна.

Если вы хотите обрабатывать повторный запрос как предупреждение или уведомление, а не как ошибку, код состояния ответа 304Не изменен иContent-Location заголовок, идентифицирующий существующий ресурс, будут такими же действительными. Когда целью является просто обеспечение того, что ресурс существует, повторный запрос будет не ошибкой, а подтверждением. Запрос не является неправильным, но просто избыточен, и клиент может ссылаться на существующий ресурс.

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

Suncat2000
источник
6
Насколько я понимаю, 304 предназначен для операций GET, чтобы помочь с кэшированием.
Синастетик
6

Ожидается, что адаптер ActiveRecord Ember-Data 422 UNPROCESSABLE ENTITYбудет возвращен с сервера. Итак, если ваш клиент написан на Ember.js, вы должны использовать 422. Только тогда DS.Errors будет заполнен возвращенными ошибками. Конечно, вы можете изменить 422 на любой другой код в вашем адаптере.

Даниэль Кмак
источник
0

406 - неприемлемо

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

Хасан Сефа Озальп
источник