HTTP 400 (неверный запрос) для логической ошибки, а не искаженного синтаксиса запроса

В спецификации HTTP / 1.1 (RFC 2616) говорится следующее о значении код состояния 400, неверный запрос (§10.4.1):

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

Похоже, что в наши дни среди некоторых API-интерфейсов на основе HTTP существует общая практика использовать 400 для обозначения логической, а не синтаксической ошибки запроса. Я предполагаю, что API делают это, чтобы различать 400 (вызванные клиентом ) и 500 (вызвано сервером). Допустимо или неправильно использовать 400 для обозначения несинтаксических ошибок? Если это приемлемо, существует ли аннотированная ссылка на RFC 2616, которая дает более полное представление о предполагаемом использовании 400?

Примеры:


person Atif Aziz    schedule 24.01.2011    source источник
comment
Почему веб-серверу следует беспокоиться о синтаксических ошибках?   -  person leppie    schedule 24.01.2011
comment
@leppie: веб-сервер должен убедиться, например, что строка запроса и заголовки правильно сформированы.   -  person Atif Aziz    schedule 24.01.2011
comment
Но это был бы неверный запрос клиента.   -  person leppie    schedule 24.01.2011
comment
@leppie: клиент всегда может отправить неверный запрос. Понятно, что в этом случае сервер ответит 400. Что неясно, так это то, является ли 400 законным ответом на правильно сформированный, но недействительный (для каждого приложения) запрос.   -  person Atif Aziz    schedule 24.01.2011
comment
@ Атиф Азиз: Если запрос может быть передан на какой-либо резервный сервер, он должен иметь ошибку 500, за исключением хорошо известных ошибок клиента, таких как сбой аутентификации или 404.   -  person leppie    schedule 24.01.2011
comment
@leppie: Похоже на ответ. :)   -  person Atif Aziz    schedule 24.01.2011
comment
В стороне, для справки в будущем: какой-то пример кода, который я видел, возвращает 400 Bad Request, когда учетные данные для входа неверны. Затем тело ответа снова включает ту же страницу входа. Это может сработать при отправке напрямую в браузер. Но, например, jQuery Mobile в этом случае просто показывает страницу с ошибкой загрузки.   -  person Arjan    schedule 22.03.2012


Ответы (8)



На ум приходит статус 422 (RFC 4918, раздел 11.2):

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

person Julian Reschke    schedule 24.01.2011
comment
RFC 4918 - это RFC WebDAV, с которым я не знаком. Можно ли повторно использовать расширения кода состояния для HTTP / 1.1 в службах HTTP, отличных от WebDAV? Раздел о совместимости HTTP-клиента, похоже, указывает на то, что является. Поддерживает ли IETF окончательный список всех (основных и расширенных) кодов HTTP, чтобы гарантировать, что какая-то другая служба, основанная на HTTP, не вводит еще больше кодов, конфликтующих с другими расширениями? - person Day; 24.01.2011
comment
Да, это хорошо. Вот почему существует реестр кодов состояния. См. http://www.iana.org/assignments/http-status-codes. - person Julian Reschke; 24.01.2011
comment
422 подходит очень близко. Единственный позор состоит в том, что он, кажется, конкретно связан с необработанным объектом, а не с необработанным запросом. Если бы он только охватывал последний, он также охватывал бы случай HTTP GET, потому что он не имеет сущности. Однако из описания 422 ясно, что 400 не подходит для логически недействительного запроса. - person Atif Aziz; 25.01.2011

HTTPbis будет обращаться к формулировке 400 Bad Request, чтобы охватить также и логические ошибки. Таким образом, 400 будет включать 422.

Из https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-18#section-7.4.1
«Сервер не может или не будет обрабатывать запрос из-за ошибки клиента (например, неправильного синтаксиса)»

person Andrei Neculau    schedule 15.10.2012

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

Только мои 2 цента ... В наши дни нам нужны юристы и судьи, чтобы интерпретировать язык в RFC :)

Спасибо, Виш

person Vish    schedule 24.01.2011

Можно утверждать, что наличие неверных данных в вашем запросе является синтаксической ошибкой, даже если ваш фактический запрос на уровне HTTP (строка запроса, заголовки и т. Д.) Синтаксически действителен.

Например, если веб-служба Restful задокументирована как принимающая POST-запросы с настраиваемым типом содержимого XML application/vnd.example.com.widget+xml, и вместо этого вы отправляете какой-то бессмысленный простой текст или двоичный файл, кажется разумным рассматривать это как синтаксическую ошибку - тело вашего запроса не в ожидаемом виде.

Я не знаю никаких официальных ссылок, подтверждающих это, хотя, как обычно, похоже, что это связано с интерпретацией RFC 2616.

Обновление: обратите внимание на измененную формулировку в RFC 7231 §6.5 .1:

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

похоже, поддерживает этот аргумент больше, чем теперь устаревший RFC 2616 §10.4.1 который сказал только:

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

person Day    schedule 24.01.2011
comment
Это, безусловно, интересный способ взглянуть на это. Как насчет запросов GET, в которых используется недопустимое значение параметра строки запроса? Можно ли сказать, что 400 можно использовать, потому что, хотя строка запроса правильно сформирована, значение параметра строки запроса имеет синтаксическую ошибку для представления приложения? - person Atif Aziz; 24.01.2011
comment
Что ж, это кажется небольшим шагом от примера POST, который я привел, но я признаю, что кажется немного неприятным делать то же самое с запросами GET, когда приложение обнаруживает, что части URL-адреса недействительны. В действительно интерфейсе Restful, использующем HATEOAS (гипертекст как движок состояния приложения), URL-адреса ресурсов не важны для клиента - клиенты просто переходят по ссылкам из других ресурсов. Но тогда большинство REST API не придерживаются этого принципа и вместо этого объясняют, какие параметры строки запроса должны быть добавлены к какому URL-адресу, поэтому я думаю, что в таких службах ответ 400 будет нормальным. - person Day; 24.01.2011

На серверах Java EE возвращается 400, если ваш URL относится к несуществующему «веб-приложению». Это «синтаксическая ошибка»? Зависит от того, что вы подразумеваете под синтаксической ошибкой. Я бы сказал да.

В английском правила синтаксиса предписывают определенные отношения между частями речи. Например, «Боб женится на Мэри» синтаксически правильно, потому что оно следует шаблону {Существительное + Глагол + Существительное}. В то время как «Боб женился на Мэри» было бы синтаксически неверным, {Существительное + Существительное + Существительное}.

Синтаксис простого URL-адреса: {протокол +: + // + сервер +: + порт}. Согласно этому синтаксически правильно "http://www.google.com:80".

Но как насчет «abc: //www.google.com: 80»? Кажется, он следует той же схеме. Но на самом деле это синтаксическая ошибка. Почему? Потому что «abc» не ОПРЕДЕЛЕННЫЙ протокол.

Дело в том, что определение того, есть ли у нас ситуация 400, требует большего, чем анализ символов, пробелов и разделителей. Он также должен распознавать допустимые «части речи».

person Panu Logic    schedule 29.08.2013

Это сложно.

Я думаю, нам следует;

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

  2. Возвращать коды диапазона ошибок, если ожидаемая мутация не произошла, т.е. не произошло DELETE или PUT ничего не изменил. Однако POST более интересен, потому что в спецификации говорится, что его следует использовать либо для создания ресурсов в новом месте, либо просто для обработки полезной нагрузки.

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

Запрос работал нормально, он попал в правила вашего приложения, клиент все сделал правильно, ETags совпали и т. Д. И т. Д.

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

Возможно, вы это разработали.

PUT { updated members list } /marketing/members

Возврат кода успеха будет означать, что «замена» ресурса сработала; GET на ресурсе отразит ваши изменения, но этого не произойдет.

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

Когда я читаю официальные коды HTTP, эти два выглядят подходящими.

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

А также

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

Хотя мы традиционно считали, что 500 - это необработанное исключение: - /

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

С такой конструкцией легче справиться.

PUT { membership add command } /accounts/groups/memberships/instructions/1739119

Затем вы можете разработать свой API так, чтобы он всегда успешно создавал инструкцию, он возвращает 201 Created и заголовок Location, и любые проблемы с инструкцией удерживаются в этом новом ресурсе.

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

Вероятно, вы уже написали API, который это делает, веб-сайт. Вы ОТПРАВЛЯЕТЕ платежную форму, и она была успешно отклонена из-за неправильного номера кредитной карты.

При использовании POST, возвращаете ли вы 200 или 201 вместе с сообщением об отклонении, зависит от того, был ли создан новый ресурс и доступен для GET в другом месте или нет.

С учетом всего вышесказанного я был бы склонен разрабатывать API-интерфейсы, которым требуется меньше PUT, возможно, просто обновляя поля данных, а действия и прочее, которые вызывают правила и обработку или просто имеют более высокую вероятность ожидаемых сбоев, могут быть разработаны для POST инструкции форма.

person Luke Puplett    schedule 23.01.2019

В моем случае:

Я получаю 400 неверных запросов, потому что я неправильно установил content-type. Я изменил тип контента, после чего смог успешно получить ответ.

До (проблема):

ClientResponse response = Client.create().resource(requestUrl).queryParam("noOfDates", String.valueOf(limit))
                .header(SecurityConstants.AUTHORIZATION, formatedToken).
header("Content-Type", "\"application/json\"").get(ClientResponse.class);

После (исправлено):

ClientResponse response = Client.create().resource(requestUrl).queryParam("noOfDates", String.valueOf(limit))
                .header(SecurityConstants.AUTHORIZATION, formatedToken).
header("Content-Type", "\"application/x-www-form-urlencoded\"").get(ClientResponse.class);
person user13012562    schedule 05.03.2020