REST: сопоставление ошибок приложения с кодами состояния HTTP

Считается ли хорошей практикой повторное использование кодов статуса RFC HTTP, как это, или мы должны создавать новые, которые точно соответствуют нашим конкретные причины ошибки?

Мы разрабатываем API веб-службы для нескольких устаревших приложений.

В дополнение к структурам данных JSON / XML в теле ответа мы стремимся возвращать коды состояния HTTP, которые имеют смысл для разработчиков веб-кешей и.

Но как подойти к сопоставлению различных классов ошибок с соответствующими кодами состояния HTTP? Все в команде согласны со следующим:

GET / package / 1234 возвращает 404 Not Found, если 1234 не существует.

GET / package / 1234 / next_checkpoint возвращает 400 неверный запрос, если next_checkpoint и 1234 допустимы для запроса, но next_checkpont здесь не имеет смысла. ..

и так далее ... но в некоторых случаях требуется более конкретная информация, чем просто 400 - например:

POST / dispatch /? for_package = 1234 возвращает 412 Precondition Failed, если существуют / dispatch и package 1234, НО 1234 еще не готов к отправке.


(Изменить: коды состояния в HTTP / 1.1 и коды состояния в WebDAV ext.)


person conny    schedule 04.03.2010    source источник


Ответы (5)


Использование HTTP в RESTful означает, что вы должны поддерживать единообразие API. Это означает, что вы не можете добавлять методы, специфичные для домена (например, GET_STOCK_QUOTE), но это также означает, что вы не можете добавлять коды ошибок, специфичные для домена (например, 499 Product Out Of Stock).

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

Янв

person Jan Algermissen    schedule 04.03.2010
comment
Итак, как такие вещи, как Webdav (который использует HTTP), сходит с рук при его расширении? Просто потому, что это не HTTP (даже если он его использует)? - person Steve Pomeroy; 04.03.2010
comment
Да, я посмотрел на расширения WebDAV, но считаю, что они очень специфичны для DAV, и я бы предпочел не использовать их повторно ... - person conny; 04.03.2010
comment
Вопрос: КАК один из наиболее распространенных веб-серверов обходится без всех этих кодов подстатуса, когда RFC говорит 3DIGIT с последующим пробелом (ами)? support.microsoft.com/kb/943891 - person conny; 04.03.2010
comment
@Steve: Расширения WebDAV единообразны. Подать заявку на любой ресурс. Расширять HTTP - это нормально, но семантика любого расширения должна иметь смысл для любого ресурса. - person Jan Algermissen; 04.03.2010
comment
@Conny: коды статуса Microsoft просто неверны. HTTP их не позволяет. - person Jan Algermissen; 04.03.2010
comment
@Conny: имейте в виду, что WebDAV не является отдельным приложением. Это расширение унифицированного интерфейса HTTP. Имеет смысл повторно использовать некоторые из этих расширений (например, 422), но некоторые просто нарушают ограничения REST (all или PROP *) или сам HTTP (COPY, MOVE). Те, которые я бы не использовал повторно. - person Jan Algermissen; 04.03.2010
comment
Подумайте, например, о PATCH. Это отличное расширение HTTP. Или иногда упоминаемые WATCH (или MONITOR) для создания pubsub с HTTP: ‹code› WATCH / my / feed Reply-To: some.org/please/send/notification/here ‹/code› янв. - person Jan Algermissen; 04.03.2010
comment
PATCH избыточен; он решает предполагаемую проблему с PUT, которой фактически не существует в RFC 2616. - person wprl; 17.05.2014
comment
Привет, wprl, какую проблему решает ПАТЧ, которого на самом деле не существует? - person Jan Algermissen; 18.05.2014

422 Unprocessable Entity - полезный код ошибки для подобных сценариев. См. Этот вопрос https://stackoverflow.com/questions/2190945/what-http-response-code-for-rest-service-on-put-method-when-domain-rules-invalid/2194786#2194786 для получения дополнительной информации.

person Darrel Miller    schedule 04.03.2010

GET / package / 1234 / next_checkpoint возвращает 400 Bad Request, если "next_checkpoint" и 1234 действительны для запроса, но next_checkpont здесь не имеет смысла ...

Это неправильный способ думать об этом URI.

URI непрозрачны, поэтому наблюдение за тем, что некоторые из них являются «действительными», а другие нет, не имеет никакого смысла с точки зрения клиента. Поэтому вам следует «просто» вернуть 404 клиенту, поскольку ресурс «package / 1234 / next_checkpoint» не существует.

person Mike    schedule 05.03.2010

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

Обновление: при дальнейшем чтении RFC для условных заголовков, таких как «if-none-match», подразумевается «procondition failed». Вместо этого я бы дал общее сообщение 400.

person Steve Pomeroy    schedule 04.03.2010
comment
Замечание по этому поводу, еще одна актуальная тема SO: stackoverflow.com/questions/1959947/ - person Steve Pomeroy; 04.03.2010
comment
Еще одна вещь, подтверждающая эту перспективу: спецификация XCAP (RFC4825 и использует HTTP) использует 400 кодов ответа, когда возникает ошибка клиента XCAP. - person Steve Pomeroy; 04.03.2010
comment
Webdav (rfc2518) также использует 400 кодов ответа, если тело запроса неверно. - person Steve Pomeroy; 04.03.2010

Собственно, делать этого вообще не стоит. Вы используете 404 Not Found правильно, но 400 Bad Request используется неправильно. 400 Bad Request согласно RFC используется только тогда, когда протокол HTTP имеет неправильный формат. В вашем случае запрос синтаксически правильный, это просто неожиданный аргумент. Вы должны вернуть 500 Server Error, а затем включить код ошибки в результат REST.

person David Pfeffer    schedule 04.03.2010
comment
Действительно? Все, что он говорит, это: «Запрос не может быть понят сервером из-за неправильного синтаксиса. Клиенту НЕ СЛЕДУЕТ повторять запрос без изменений ». Он не указывает, связана ли ошибка с HTTP или битом запроса на уровне приложения. Ошибка сервера 500 неспецифична для запросов, в которых клиент отправил неверные данные. Я склонен думать, что 500 ошибок - это то, что никогда не должно происходить (ошибки программирования и т.п.), а серия 4xx означает недопустимый ввод. - person Steve Pomeroy; 04.03.2010
comment
400-я серия предназначена для случаев, когда клиент совершил ошибку. Серия 500 предназначена для случаев, когда сервер допустил ошибку. В этих сценариях сервер не вызывал ошибку, поэтому 500 неверно. - person Darrel Miller; 04.03.2010
comment
Синтаксис, на который ссылается RFC, - это синтаксис HTTP. Вы смотрите на HTTP RFC; как это может говорить об ошибке синтаксиса уровня приложения для конструкции более низкого уровня OSI? Ошибка сервера здесь уместна, потому что сервер - это тот, кто не может продолжить. Клиент может быть виноват с точки зрения приложения, но с точки зрения HTTP это ошибка сервера в том, что диалог не продолжается. - person David Pfeffer; 04.03.2010
comment
Я не совсем уверен, что синтаксис означает строго синтаксис HTTP или синтаксис комбинированного запроса, включая такие вещи, как тело вашего запроса. RFC не уточняет, и язык довольно расплывчатый. На практике вы действительно хотели бы иметь какой-то способ различать запросы, которые не могут быть выполнены из-за сервера или из-за какой-либо ошибки на клиенте. Использование 500 против 400 кажется наиболее целесообразным в этих случаях. - person Steve Pomeroy; 04.03.2010
comment
@ Стив Помрой, вы должны учитывать разделение слоев. Вы бы отправили TCP FIN + SYN, потому что вам не нравится передача по протоколу HTTP? Точно так же вы не стали бы отправлять HTTP-код, указывающий на ошибку клиента, если вам не нравятся решения прикладного уровня. - person David Pfeffer; 04.03.2010
comment
@David Pfeffer, да, но HTTP RFC более свободно описывает, что означают определения кода состояния. Взгляните на RFC, которые я процитировал ниже, которые используют ответ статуса 400 для своих ошибок прикладного уровня. В конце концов, если вы говорите, что все ошибки клиента уровня приложения должны быть ответами серии 500, тогда не существует простого способа передать свои собственные ошибки клиента уровня приложения без создания нового кода состояния HTTP серии 4xx. Кроме того, другие коды серии 4xx относятся к несинтаксическим ошибкам клиента. - person Steve Pomeroy; 04.03.2010
comment
Вот тут-то и застряла дискуссия в нашем офисе ... Впрочем, приятно видеть ваши аргументы :) - person conny; 04.03.2010
comment
@David Pfeffer HTTP - это протокол прикладного уровня. Коды ответов предназначены для использования распределенными приложениями для индикации ошибок приложения. - person Darrel Miller; 05.03.2010
comment
@ Даррел Миллер: Я понимаю, что HTTP - это действительно протокол прикладного уровня, я просто говорю, что это протокол, на который накладываются другие вещи. OP должен использовать в ответе собственные коды ошибок, а не коды HTTP. - person David Pfeffer; 05.03.2010
comment
В значительной степени «точка» RESTful HTTP состоит в том, чтобы обеспечить / соответствовать унифицированным механизмам, с помощью которых клиенты и серверы должны взаимодействовать (т.е. нечего добавлять / накладывать сверху). Приложения, использующие HTTP в стиле REST, не «накладываются» поверх HTTP; они (намеренно) ограничены и управляются его архитектурой. Клиенты управляются в приложениях RESTful путем обмена (гипермедиа) представлениями через (не поверх) HTTP. - person Mike; 05.03.2010
comment
Все очень хорошо, но как клиенту узнать, является ли полезная нагрузка этого 4xx гипермедиа, которую он ожидает, или гипермедиа tomcat, сообщающего, что URL-адрес не был определен? - person bmargulies; 12.05.2011