Следует ли использовать коды состояния HTTP для представления ошибок бизнес-логики на сервере?

20

Я нахожусь на перепутье с некоторым дизайном API для клиента (JS в браузере), чтобы общаться с сервером. Мы используем HTTP 409 Conflict для представления сбоя действия из-за действующей блокировки безопасности. Замок Satefy предотвращает случайное внесение разработчиками изменений в производственные системы наших клиентов. Мне было поручено немного более изящно обрабатывать 409-е на клиенте, чтобы указать, почему не удался конкретный вызов API.

Мое решение состояло в том, чтобы обернуть обработчики сбоев любого из наших вызовов AJAX, которые будут отображать уведомление на клиенте, когда что-то выходит из строя из-за 409 - это все хорошо и работает хорошо наряду с другими ошибками 4XX и 5XX, которые используют тот же механизм.

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

Что подводит меня к перекрестку: следует ли использовать коды состояния HTTP даже для представления ошибок бизнес-логики? Этот вопрос решает ту же проблему, с которой я сталкиваюсь, но он не получил большой тяги. Как указано в связанном ответе, я склоняюсь к использованию HTTP 200 OK с соответствующим телом для представления ошибок в бизнес-логике.

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

Джо Шанахан
источник
3
Я не решаюсь опубликовать мое простое мнение в качестве ответа. Короче говоря: я обычно избегаю использовать коды состояния HTTP для представления ошибок бизнеса. Они должны относиться только к состоянию связи между клиентом и сервером. Подходящий код состояния для возврата ошибок проверки или бизнес-логики будет 400 Bad Request. Причина такого разделения заключается в том, что будущие системы, разработчики или читатели документов могут быть сбиты с толку вашим отклонением от мирового стандарта.
Иво Куманс
@ IvoCoumans: пожалуйста, сделайте это ^ ответом, чтобы я мог проголосовать. 400 Bad Requestв качестве общего кода HTTP кажется наилучшим для охвата ошибок бизнес-логики как класса.
9000
Личные предпочтения, но я склонен использовать, 400 Bad Requestкогда данные отсутствуют или не могут быть прочитаны / проанализированы. Т.е. сами данные запроса в некотором роде плохие.
Кейси
Пожалуйста, уточните, что вы подразумеваете под "ошибкой бизнес-логики". Это очень расплывчато. Вы имеете в виду ввод, который недопустим в соответствии с (правильными) проверками проверки данных, ввод, который может быть действительным в какой-то другой момент времени, но недействительным в текущем состоянии, или ошибка в бизнес-логике, когда он отклоняет допустимый ввод?
jpmc26
@ jpmc26 Я был намеренно расплывчатым, так как это был общий вопрос. Серверы справились с запросом просто отлично, но решили, что запрос / утверждение не имеет смысла.
Джо Шанахан

Ответы:

19

Кейси раскрывает главное.

Ключевая идея в любом веб-API: вы адаптируете свой домен, чтобы он выглядел как хранилище документов. GET / PUT / POST / DELETE и так далее - все это способы взаимодействия с хранилищем документов.

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

2xx совершенно не подходит

Класс статуса 2xx (Успешный) указывает, что запрос клиента был успешно получен, понят и принят.

5xx тоже не подходит

Класс кода состояния 5xx (Ошибка сервера) указывает, что сервер знает, что он допустил ошибку

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

Ошибки бизнес-логики (это означает, что бизнес-инвариант не позволяет предлагаемое редактирование в настоящее время), вероятно, 409

Код состояния 409 (Конфликт) указывает, что запрос не может быть выполнен из-за конфликта с текущим состоянием целевого ресурса. Этот код используется в ситуациях, когда пользователь может разрешить конфликт и повторно отправить запрос. Сервер ДОЛЖЕН генерировать полезную нагрузку, которая включает в себя достаточно информации, чтобы пользователь мог распознать источник конфликта.

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

Мое решение состояло в том, чтобы обернуть обработчики сбоев любого из наших вызовов AJAX, которые будут отображать уведомление на клиенте, когда что-то выходит из строя из-за 409 - это все хорошо и работает хорошо наряду с другими ошибками 4XX и 5XX, которые используют тот же механизм.

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

То есть, в конце концов, как это сделает хранилище документов?

409  Conflict

your proposed change has been declined because ${REASON}.  
The following resolution protocols are available: ${LINKS[@]})

Тот же подход с a 400 Bad Requestтакже будет приемлемым; что примерно "переводит на" возникла проблема с вашим запросом. Мы не можем быть обеспокоены, чтобы выяснить, какой код статуса подходит лучше всего, так что вот и все. Смотрите полезную нагрузку для деталей. "

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

Спецификация WebDAV включает эту рекомендацию

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

Я не верю, что это вполне совпадает (хотя я согласен, что 400в качестве альтернативы это вызывает некоторые сомнения ). Моя интерпретация 422означает, что «вы отправили неправильную сущность», где 409«вы отправили сущность в неправильное время».

Другими словами, 422указывает на проблему с сообщением запроса, рассматриваемым изолированно, где 409указывается, что сообщение запроса конфликтует с текущим состоянием ресурса.

Обсуждение Беном Надалем 422 может быть полезным для рассмотрения.

VoiceOfUnreason
источник
5
« Вы адаптируете свой домен так, чтобы он выглядел как хранилище документов » - мне бы очень хотелось, чтобы люди прочитали это и полностью поняли все последствия и последствия, прежде чем они решат (или против) REST. В самом деле.
JensG
«Ошибки бизнес-логики» для меня звучат как «неверный ввод», который обычно является прямым числом 400, поскольку для него нет более конкретного кода ошибки. Если это не ввод, который является недействительным, то на сервере есть ошибка и 500 подходит. Ваш ответ, кажется, предполагает слишком много о природе "ошибки бизнес-логики".
jpmc26
Я бы использовал 422. Ввод действителен, поэтому 400 не правильный код ошибки для использования
Конрад
19

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

Поэтому я рекомендую использовать коды ошибок HTTP для категорий ошибок, но выбрать конкретную ошибку для сбоев бизнес-логики (например, 409 Conflict ... 200 OK будет вводить в заблуждение здесь) и включить в ответ данные, указывающие на конкретную бизнес-ошибку , Убедитесь, что это часть содержимого ответа, а не текста статуса, поскольку некоторые браузеры игнорируют пользовательский текст статуса. Язык, который я люблю использовать, имеет типы объединения, которые удобны для представления сообщений. Но вы также можете определить строковые константы для случаев ошибки.

Примеры

// error with text response
409 Conflict "safety_lock_engaged"
409 Conflict "customer_not_eligible_for_selected_discount"
// warning with JSON response
202 Accepted { "backorderedProductIds": [ 37, 476 ] }
Кейси Спикман
источник
Коды состояния 4xx выше 400 имеют очень специфические значения. Выберите 400, если ваш случай не охватывается другими.
jpmc26
@ jpmc26 Если я не использую коды состояния таким образом, они никогда не используются. Но не стесняйтесь использовать их правильно и правильно в своих ответах.
Кейси
В каком-то смысле ты прав. Они никогда не используются. Значения, выбранные для конкретных кодов, кажутся не слишком распространенными для большинства приложений. Это нормально. Есть много исключений, которые мы никогда не пишем для отлова кода.
jpmc26
@ jpmc26 Ну, исключения - не самая лучшая модель для подражания . Но конечно, давай.
Кейси
Не выбрасывать или перехватывать для определенных типов исключений является аналогом того, что никогда не используются определенные коды HTTP или любые другие коды ошибок. Я предполагал, что это будет очевидно. Является ли модель исключения «лучшей», совершенно не имеет значения.
jpmc26
5

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

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

Кстати, его 409следует использовать, когда ресурс изменился, когда вы редактировали его и пытались сохранить его снова.

Иво Куманс
источник
4

Вы можете использовать «Неверный запрос» и включить идентификатор нарушенного бизнес-правила, а также некоторые подробности в теле ответа.

noneconnex
источник
Я не знаю, почему за это проголосовали. Вот как компании могут возвращать бизнес-исключения.
Скадуш