Может ли веб-приложение возвращать 400 Bad Request при некорректных параметрах?
От: Geri Россия http://web-notes.ru/
Дата: 02.10.12 07:14
Оценка:
Довольно часто при разработке веб-приложений возникает необходимость выдать пользователю какой-то ответ, означающий, что пользователь не передал какой-то обязательный параметр или переданный параметр имеет недопустимое значение. При беглом просмотре списка кодов ошибок HTTP, кажется, что для этого наиболее подходит код 400 Bad Request. Однако, в описании к нему говорится, что этот код используется, когда запрос не может быть понят сервером из-за синтаксической ошибки в запросе. Например, какие-то недопустимые символы в URI, нет обязательного заголовка "Host" в запросе HTTP/1.1, и т.п. То есть все те ошибки, которые обрабатывает веб-сервер ещё до вызова скрипта-обработчика (например, PHP). Следовательно сам PHP-скрипт не должен выдавать код 400, т.к. если PHP-скрипт вызвался, значит запрос прошел формальную проверку на уровне веб-сервера и с синтаксисом у него всё в порядке.

Для ряда ситуаций нас вполне может спасти код 404 Not Found (даже когда речь идёт о query-параметре, т.к. query является частью URI). Но не всегда. Например, в POST-запросе не пришел параметр, который должен был придти, без которого запрос теряет всякий смысл -- посылать 404 в данном случае было бы неправильно, т.к. сам URL правильный. Обычно в таких случаях разработчики просто кидают какое-то общее исключение, которое потом где-то на уровне index.php или Front-контроллера перехватывается и трансформируется в ошибку 500 Internal Server Error. Иногда, вместо нее шлют 503 Service Unavailable, чтобы показать тем самым временность проблемы (если проблема связана с каким-то сбоем или ошибкой в коде), чтобы типа поисковики не удаляли сайт из индекса. На мой взгляд это неправильно, т.к. статус ошибки фактически не соответствует её сути.

Главная проблема в том, что 500-ые ошибки в такого рода ситуациях говорят клиенту о том, что проблема находится на стороне сервера, тогда как 400-ые ошибки говорят в основном о проблеме на стороне клиента. RFC-2616 говорит о том, что при получении клиентом 400-ой ошибки клиент НЕ ДОЛЖЕН повторять запрос без изменения запроса. И действительно, если запрос изначально некорректный, сколько его не повторяй -- результат не изменится. Тогда как при получении 500 ошибки клиент может продолжать "долбить" сервер снова и снова в то время как проблема -- в неправильном запросе. RFC-2616 очень скуп на описание данной ошибки и ограничивается всё тем же синтаксисом и приводом пары частных примеров. Однако, что такое ошибка синтаксиса? Можно ли считать отсутствующий или неправильный параметр, который требуется в каком-то частном обработчике, синтаксической ошибкой? Я раньше считал, что нет, хотя и были сомнения. Но недавно я обнаружил, что Facebook возвращает 400 Bad Request в случае если при авторизации через OAuth передан неправильный query-параметр с кодом, и об этом написано в официальной документации. То есть фэйсбук считает неправильный GET-параметр синтаксической ошибкой.

Кто-нибудь может дать пояснение по данной теме? Вопрос весьма не тривиальный, на большинстве форумов топик бы засрали прыщавые быдлокодеры, не дав ни одного ценного ответа. На RSDN вроде бы достаточно зрелая аудитория, поэтому вся надежда на неё. Меня интересует не личный опыт применения кода 400 Bad Request теми или иными программистами, я понимаю, что из скрипта можно послать любой код HTTP, а официальное подтверждение допустимости такого использования со ссылкой на какой-нибудь RFC или IETF.
-- С уважением, Павел Мелехов, Екатеринбург.
http 400 bad request rfc-2616
Re: Может ли веб-приложение возвращать 400 Bad Request при некорректных параметр
От: A13x США  
Дата: 02.10.12 10:11
Оценка: 6 (1) +1
Здравствуйте, Geri, Вы писали:

G>...


Из REST API Design Guide:

Rule: 400 (“Bad Request”) may be used to indicate nonspecific failure
400 is the generic client-side error status, used when no other 4xx error code is
appropriate.
For errors in the 4xx category, the response body may contain a docu-
ment describing the client’s error (unless the request method was
HEAD). See “Error Representation” on page 68 for error response body
design.


Короче, я бы не парился сделал бы обработку ошибки на неверные параметры запроса путем возврата 400 статуса + описание подтипа ошибки в теле.

Рекомендую почитать.
Re: Может ли веб-приложение возвращать 400 Bad Request при некорректных параметр
От: okman Беларусь https://searchinform.ru/
Дата: 02.10.12 10:29
Оценка: 5 (2) -1
Здравствуйте, Geri.

В контексте данного вопроса HTTP можно рассматривать, как транспорт для протоколов более высокого уровня.
И в архитектурном плане очень сомнительно использовать транспорт для сигнализации о логических
ошибках и разделять с ним его коды состояний. Представьте, что вместо HTTP использовался бы TCP и
тогда, по аналогии, сервер в случае некорректно сформированного запроса отправлял бы FIN- или RST-пакет.
Можно ли назвать такое решение правильным ? Нет. В идеале транспорт вообще не должен "знать" о том,
что происходит наверху и отвечать только за передачу данных. Успешная передача — код из группы 200.
Неуспешная — другой код, в зависимости от обстоятельств. И так достигается определенная гибкость.
Например, при смене транспорта не придется переделывать систему обработки ошибок.

Коды состояний HTTP не смогут обеспечить клиента точной информацией о том, на каком этапе обработки запроса
произошел сбой — на транспортном или логическом. Если, к примеру, и front end, и back end сервера могут
отдавать "500 Internal Server Error", то рано или поздно наступает ситуация, когда клиент получает такой
ответ и не знает, от кого именно он пришел и по каким правилам обрабатывать его содержимое. В то же время
"надпротокольные" сообщения об ошибках, возвращенные с кодом 200, могут быть и более структуированными, и
более информативными, и вообще более соответствующими духу системы, в которой они используются.

Я встречал мнение, что можно использовать зарезервированные коды HTTP-состояний. Например, диапазон
512-599 в настоящее время свободен. Но это, во-первых, решает проблему лишь частично (точнее, отодвигает
ее на более поздний срок), а во-вторых, никто не гарантирует, что завтра-послезавтра IANA не присвоит
этим кодам осмысленные значения и семантику, после чего снова возможны проблемы.

Что касается RFC — я могу лишь привести выдержку из документа, касающуюся рекомендаций
правильной организации уровней в модели OSI:

ISO/IEC 7498-1

6.2 The principles used to determine the seven layers in the Reference Model.

...

c) Create separate layers to handle functions that are manifestly different in the
process performed or the technology involved.

d) Collect similar functions into the same layer.

...

j) Allow changes of functions or protocols to be made within layer without affecting other layers; and

k) Create for each layer, boundaries with its upper and lower layers only.

По-моему, очень неплохая отправная точка.
Re[2]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Geri Россия http://web-notes.ru/
Дата: 03.10.12 09:40
Оценка: +1
Здравствуйте, okman, Вы писали:

O>В контексте данного вопроса HTTP можно рассматривать, как транспорт для протоколов более высокого уровня.

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

Буквально до вчерашнего дня я считал примерно так же, как и вы. Я считал, что 400-ый код -- это код ответа на некорректный с точки зрения HTTP-протокола запрос, и использовать его для индикации каких-то ошибок уровня логики приложения неправильно. Но вчера во мне закралось сомнение, которое почти полностью оправдалось после ответа A13x. Если бы мы использовали HTTP-протокол как транспорт для более высокоуровнего протокола, то, например, в случае не нахождения запрашиваемого объекта нам бы следовало возвращать не 404-ый код, а "200 OK", а в теле ответа некое закодированное сообщение, содержащие код ошибки от высокоуровнего протокола, который бы разбирался бы принимающей стороной в соответствии с высокоуровневым протоколом.

Но дело в том, что мы не используем HTTP как транспорт для протоколов более высокого уровня, PHP скрипт не создает новый уровень протокола (по крайней мере при создании обычных сайтов, на которые ходят браузерами). HTTP -- это уже протокол высокого уровня, и мы используем его самого напрямую, не как только транспорт. Поэтому работу веб-сервера и PHP-скрипта следует рассматривать как единое целое. В конце-концов, такое разделение на веб-сервер и скрипт всего лишь частный случай. Мы можем написать на Си++ приложение, которое при запуске будет открывать 80-ый порт, и отвечать на HTTP-запросы какими-то осмысленными динамически создаваемыми HTTP-ответами. Клиент (пользователь) в общем случае не знает как архитектурно реализовано приложение. Он обращается с ним как с черным ящиком, в который можно посылать какие-то HTTP-запросы и получать какие-то HTTP-ответы. По кодам ответов пользователь может узнавать о том, что он что-то делает не так, некоторые дополнительные предписания и рекомендации по дальнейшему использованию.

Ошибки синтаксиса в общем-то могут быть не ограничены тем синтаксисом, который содержится в RFC2616. HTTP -- это расширяемый протокол, поэтому на мой взгляд вполне допустимо вводить не только новые HTTP-коды и новые методы HTTP-запросов в своих приложениях, но и дополнительные правила синтаксиса, которые требуются для правильной обработки того или иного запроса. Понятие синтаксиса это ведь не только формальное соответствие строки некоемому шаблону регулярного выражения, но и сочетаемость отдельных частей запроса между собой (как сочетаемость слов в предложениях). К тому же в самом RFC2616 даётся указание о том, что 400-ый код следует посылать всякий раз, когда клиент использует версию HTTP-протокола 1.1 и при этом в запросе отсутствует заголовок "Host". Наличие заголовков в HTTP вещь опциональная, так что тут уже идет некий элемент логического несоответствия некоего параметра (заголовка) некоемому запросу.

O>Я встречал мнение, что можно использовать зарезервированные коды HTTP-состояний. Например, диапазон

O>512-599 в настоящее время свободен. Но это, во-первых, решает проблему лишь частично (точнее, отодвигает
O>ее на более поздний срок), а во-вторых, никто не гарантирует, что завтра-послезавтра IANA не присвоит
O>этим кодам осмысленные значения и семантику, после чего снова возможны проблемы.

Задействовать не зарезервированные коды -- это последнее дело. Клиент всё равно не поймет их, либо поймёт их неправильно, если выбранный нами код когда-нибудь станет каким-нибудь расширением стандарта, описанным в каком-нибудь отдельном RFC, которое кто-то может поддерживать, кто-то нет. В любом случае, разработчики браузеров не будут считаться с тем расширением стандарта, которое придумал какой-то отдельно взятый программист, нигде не задокументировал, а просто стал по тихому использовать в своих приложениях. При этом в RFC2616 сказано, что для всех неизвестных кодов HTTP клиенты должны учитывать лишь первую цифру, а интерпретировать их как код x00, где x — первая цифра неизвестного кода. То есть, например, код "456 Missing Query Parameter" будет для браузера эквивалентен ответу "400 Bad Request". С той лишь разницей, что ответы с неизвестными кодами запрещено кэшировать.

O>Что касается RFC — я могу лишь привести выдержку из документа, касающуюся рекомендаций

O>правильной организации уровней в модели OSI:
O>По-моему, очень неплохая отправная точка.

Боюсь, что модель OSI здесь не очень уместна.
-- С уважением, Павел Мелехов, Екатеринбург.
Re[2]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Geri Россия http://web-notes.ru/
Дата: 03.10.12 09:42
Оценка:
Здравствуйте, A13x, Вы писали:

A>Здравствуйте, Geri, Вы писали:


A>Из REST API Design Guide:

A>Rule: 400 (“Bad Request”) may be used to indicate nonspecific failure
A>Короче, я бы не парился сделал бы обработку ошибки на неверные параметры запроса путем возврата 400 статуса + описание подтипа ошибки в теле.

Это как раз то, что я и надеялся получить в ответ. Спасибо!
-- С уважением, Павел Мелехов, Екатеринбург.
Re[3]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: okman Беларусь https://searchinform.ru/
Дата: 03.10.12 12:17
Оценка: 4 (1) +1 -2
Здравствуйте, Geri, Вы писали:

G>Буквально до вчерашнего дня я считал примерно так же, как и вы. Я считал, что 400-ый код -- это код ответа на некорректный с точки зрения HTTP-протокола запрос, и использовать его для индикации каких-то ошибок уровня логики приложения неправильно. Но вчера во мне закралось сомнение, которое почти полностью оправдалось после ответа A13x. Если бы мы использовали HTTP-протокол как транспорт для более высокоуровнего протокола, то, например, в случае не нахождения запрашиваемого объекта нам бы следовало возвращать не 404-ый код, а "200 OK", а в теле ответа некое закодированное сообщение, содержащие код ошибки от высокоуровнего протокола, который бы разбирался бы принимающей стороной в соответствии с высокоуровневым протоколом.


А веб-сервисы обычно именно так и работают, обратите внимание.
Когда мы в каком-нибудь интернет-магазине жмем "add to card", забыв выбрать товар, или пытаемся
залогиниться, указав неверный пароль, — то есть, совершаем логически ошибочное действие, — сервер,
тем не менее, возвращает успешный код "HTTP/1.1 200 OK" (транспорт), а в теле ответа — HTML с
соответствующим сообщением о том, что именно произошло (логика). С картинками и пояснительными знаками.
Это и есть разделение. Если сделать по-другому, чтобы сервер возвращал "400 Bad Request" или "404 Not
Found", то клиент не сможет узнать, по какой именно причине произошла ошибка и что делать дальше.

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

Так что разделение, даже если оно местами кажется весьма условным, может оказаться очень полезным.
В самих браузерах сетевые компоненты и компоненты, отвечающие за работу с HTML (рендеринг), стараются по
возможности изолировать друг от друга. А в серверных технологиях есть понятие frontend-а и backend-а.
И это неспроста.

G>Но дело в том, что мы не используем HTTP как транспорт для протоколов более высокого уровня, PHP скрипт не создает новый уровень протокола (по крайней мере при создании обычных сайтов, на которые ходят браузерами). HTTP -- это уже протокол высокого уровня, и мы используем его самого напрямую, не как только транспорт.


Это как ? У меня ощущение, что мы друг друга не совсем понимаем.
Вы же передаете по HTTP какие-то осмысленные данные ? Тот же HTML/XML/JSON или просто текст ?
Вот эти данные и являются тем самым протоколом высокого уровня.

G>В конце-концов, такое разделение на веб-сервер и скрипт всего лишь частный случай. Мы можем написать на Си++ приложение, которое при запуске будет открывать 80-ый порт, и отвечать на HTTP-запросы какими-то осмысленными динамически создаваемыми HTTP-ответами.


Это ничего не меняет. Разделение на уровни — понятие чисто архитектурное. Можно намешать в кучу работу с HTTP,
многопоточность, кэширование и туда же понапихать серверную логику, а еще load balancer.
А можно аккуратно разбить это все на слои, занимающиеся каждый строго своей зоной ответственности и
разместить их так, чтобы они не зависели один от другого.

G>Клиент (пользователь) в общем случае не знает как архитектурно реализовано приложение. Он обращается с ним как с черным ящиком, в который можно посылать какие-то HTTP-запросы и получать какие-то HTTP-ответы. По кодам ответов пользователь может узнавать о том, что он что-то делает не так, некоторые дополнительные предписания и рекомендации по дальнейшему использованию.


Если под клиентским ПО подразумевается браузер, тогда да, лучше оставить коды состояний, потому что
браузер ни с чем иным работать и не умеет, если не считать HTML. А если речь идет о специальном клиентском
приложении, то здесь возможностей гораздо больше.
Re[4]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Geri Россия http://web-notes.ru/
Дата: 04.10.12 10:11
Оценка: +1
Здравствуйте, okman, Вы писали:

O>Когда мы в каком-нибудь интернет-магазине жмем "add to card", забыв выбрать товар, или пытаемся

O>залогиниться, указав неверный пароль, — то есть, совершаем логически ошибочное действие, — сервер,
O>тем не менее, возвращает успешный код "HTTP/1.1 200 OK" (транспорт),

Ну, мало ли что там возвращают какие-то сайты. У нас некоторые сайты при не найденной странице возвращают 200 OK. В результате этого в поисковой выдаче на этот сайт куча ссылок на страницы с сообщением о не найденной странице, потому что поисковик думает, что эти страницы содержат полезный текст. Или вместо ответа 404 делают редирект (303) на страницу "/404.php", что не многим лучше.

Почему интернет-магазины так делают? Может быть проблема в том, что просто "мужики-то не знают"? Я вот не знал, что 400 код можно использовать в своих приложениях, а неправильно заполненную форму и за HTTP-ошибку-то не считал. А интернет-сервисы зачастую пишут индусы, поэтому от них ещё и не такое ожидать можно. Поэтому я бы не хотел опираться на то как делают другие, а хотел бы опираться на стандарты. Иными словами, опираться на авторитет истины, а не на истину авторитетов. Может быть если начать выдавать код 400 в ответ на неправильно введенный пароль, то браузер не будет предлагать его сохранить? Меня лично это ужасно раздражает. Для пользователя при этом визуально ничего не поменяется.

O>Это и есть разделение. Если сделать по-другому, чтобы сервер возвращал "400 Bad Request" или "404 Not

O>Found", то клиент не сможет узнать, по какой именно причине произошла ошибка и что делать дальше.

Это вовсе не так. Мы можем вернуть статус 400 Bad Request, "а в теле ответа — HTML с соответствующим сообщением о том, что именно произошло". Пользователь браузера увидит страницу, полученную с кодом 400, точно так же, как страницу, полученную с кодом 200. Мы также можем учитывать заголовок Accept и вернуть в соответствии с ним не HTML, а к примеру, картинку с изображением не найденной картинки. Коды статусов нужны не для пользователя, а для клиентов (браузеров, поисковых ботов, downloader'ов и т.п.)

O>Другой момент заключен в том, что у кодов HTTP своя семантика, которая может использоваться компонентами,

O>такими как браузерами или прокси-серверами, в противоречии с логикой веб-сервиса, явно или неявно.
O>Например, по RFC 2616 клиенту не рекомендуется повторять один и тот же запрос, в ответ на который
O>пришел код 400. И какой-нибудь прокси-сервер, зная эту рекомендацию, запросто может закэшировать
O>ответ на запрос и отдавать его без изменений еще очень долгое время, даже если это идет вразрез с
O>логикой веб-сервиса и без участия прокси такой запрос мог быть успешно завершен намного раньше.

Не вижу в этом никакой проблемы. Если пользователь вводит неправильный пароль, то не будет ничего ужасного если ответы на все последующие запросы к веб-серверу с тем же неправильным паролем будут взяты из кэша. Причем не обязательно кэша прокси, можно кэша браузера. Зачастую так оно и бывает. Если вы не нажимаете явно F5 на странице, а просто переходите по ссылке, которая ранее отдавалась с кодом 404, то браузер скорее всего возьмет этот ответ из своего кэша, а к реальному серверу даже не обратится.

Но, к счастью, этим есть возможность эффективно управлять при помощи заголовка "Cache-Control", в котором можно например запретить кэширование, в том числе отдельно для прокси, если вы хотите, чтобы ошибки 4xx в каких-то отдельных случаях не кэшировались.

Однако, стоит сделать оговорку. В моём понимании, код 400 допустимо выдавать лишь в тех случаях, когда противоречие содержится в самом запросе, а не вытекает из ранее сделанных запросов или в результате сохранения состояния через механизмы сессий. Когда нам в запросе не приходит обязательный параметр или когда параметр имеет заведомо недопустимое значение, то абсолютно безопасно выдавать 400 Bad Request и пофиг что оно может закэшироваться (это даже хорошо если оно закэшируется -- меньше нагрузка на наш сервер). А вот в случае с неправильным паролем всё уже не так однозначно. Ведь пользователь может (например, через другой браузер) зайти на сайт и поменять пароль, а первый браузер не будет знать об этом и посему может закэшировать ответ. Поэтому логично вместе со статусом 400 запрещать кэширование заголовком Cache-Control в случаях, когда повторное выполнение запроса теоретически может привести к успеху. Но этого можно не делать, когда запрос выполняется методом POST (а авторизация как правило именно этим методом выполняется), т.к. POST-запросы никогда не кэшируются. Так что кэширование не проблема. Собственно проблема кэширования (если она есть) абсолютно одинаковая что для статуса 200, что для 400. Если вы имеете проблему с кэшированием, отвечая статусом 400, то вы получите её и отвечая статусом 200.

G>>Но дело в том, что мы не используем HTTP как транспорт для протоколов более высокого уровня, PHP скрипт не создает новый уровень протокола (по крайней мере при создании обычных сайтов, на которые ходят браузерами). HTTP -- это уже протокол высокого уровня, и мы используем его самого напрямую, не как только транспорт.


O>Это как ? У меня ощущение, что мы друг друга не совсем понимаем.

O>Вы же передаете по HTTP какие-то осмысленные данные ? Тот же HTML/XML/JSON или просто текст ?
O>Вот эти данные и являются тем самым протоколом высокого уровня.

Да, при условии, что с обоих сторон есть договоренность о формате этих данных, реализующая этот самый высокоуровневый протокол. Если же мы просто возвращаем HTML обычному браузеру (живому пользователю), то никакого протокола здесь нет. Или вы считаете человека действующим участником (объектом) этого высокоуровнего взаимодействия?

Кстати, создавая свой высокоуровневый протокол поверх HTTP, никто не мешает частично интегрировать его в HTTP. Например, при успешном запросе возвращать 200 OK, а при ошибке возвращать, к примеру, 500, а в теле ответа JSON с расшифровкой ошибки. Это конечно нарушит изоляцию слоя и затруднит в дальнейшем перенос на другой "низкоуровневый" протокол, но упростит обработку ответов, т.к. в каких-то случаях нам не нужно будет парсить JSON, чтобы понять, что произошла ошибка. Статус HTTP может просто дублировать смысл ответов высокоуровнего протокола, а не заменять их. Тогда не будет никаких проблем при переезде на другой транспорт, а все различия будут скрыты в реализациях адаптеров, обладающих единым интерфейсом.

O>Это ничего не меняет. Разделение на уровни — понятие чисто архитектурное. Можно намешать в кучу работу с HTTP,

O>многопоточность, кэширование и туда же понапихать серверную логику, а еще load balancer.
O>А можно аккуратно разбить это все на слои, занимающиеся каждый строго своей зоной ответственности и
O>разместить их так, чтобы они не зависели один от другого.

К слову сказать, не всё и не всегда можно разбить на такие вот независимые слои. Например, невозможно сделать эффективное кэширование отдельно от серверной логики, т.к. только серверная логика может знать можно ли кэшировать данный контент, и если да, то на сколько и каким именно способом. Под способом кэширования я имею в виду кэширование данных извлеченных из базы, загруженных с другого сайта, посчитанных в оперативной памяти, или же кэшировать конечный срендеренный HTML или его части, или же использовать client-side кэширование (при помощи механизма ETag/Last-Modified:If-None-Match/If-Modified-Since). Нельзя просто взять и завернуть сайт в слой кэширования как в обертку, т.к. это будет либо неэффективно, либо неизбежно приведет к ошибкам, связанным с нежелательным кэшированием.

O>Если под клиентским ПО подразумевается браузер, тогда да, лучше оставить коды состояний, потому что

O>браузер ни с чем иным работать и не умеет, если не считать HTML. А если речь идет о специальном клиентском
O>приложении, то здесь возможностей гораздо больше.

Я говорю в контексте браузера.
-- С уважением, Павел Мелехов, Екатеринбург.
Re[5]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Centaur Россия  
Дата: 04.10.12 11:02
Оценка:
Здравствуйте, Geri, Вы писали:

G>Может быть если начать выдавать код 400 в ответ на неправильно введенный пароль, то браузер не будет предлагать его сохранить?


Неправильный пароль — это не 400 Bad Request. Это 403 Вам Нельзя.
Re[6]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Geri Россия http://web-notes.ru/
Дата: 04.10.12 11:07
Оценка:
Здравствуйте, Centaur, Вы писали:

G>>Может быть если начать выдавать код 400 в ответ на неправильно введенный пароль, то браузер не будет предлагать его сохранить?

C>Неправильный пароль — это не 400 Bad Request. Это 403 Вам Нельзя.

Полностью согласен, моя ошибка.
-- С уважением, Павел Мелехов, Екатеринбург.
Re[4]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: A13x США  
Дата: 04.10.12 11:28
Оценка: +1
Здравствуйте, okman, Вы писали:

O>...

O>А веб-сервисы обычно именно так и работают, обратите внимание.

Если имеются в виду SOAP-based веб-сервисы, то на мой взгляд это не очень хороший пример REST API (почему — отдельная спорная тема).
Я бы здесь не следовал каким-то канонам, а выбирал то, что удобнее. Ну и смотрел как сделано у "крутых пацанов".

К примеру возьмем twitter API:


Bad Request The request was invalid. An accompanying error message will explain why...

Re: Может ли веб-приложение возвращать 400 Bad Request при некорректных параметр
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.12 04:31
Оценка: 18 (2) -1
Здравствуйте, Geri.

Я полностью согласен с A13x.

Философия: Искусственно разделять слои в приложениях не нужно. Полное использование возможностей нижележащего протокола — вот путь к успеху. Не надо слишком думать о том, что будет, если мы заменим транспортный протокол. Такая замена, скорее всего, потребует существенной переработки и прикладного протокола — потому, что идеальных абстракций не бывает. Ну вот, простой пример — если я пишу приложение поверх TCP, то я буду мучиться с самодельным кэшированием. А если я пишу поверх HTTP, то это будет преступной потратой ресурсов. Вместо этого нужно опираться на Cache-Control и Conditional Get.

Практика: как вы верно отметили, клиенту всё равно, какая там архитектура на серверной стороне. Есть некоторые соглашения. В частности, коды 4xx означают "виноват клиент", а коды 5xx — "виноват сервер".
В принципе, сервису достаточно кодов 400 и 500 для обработки "прикладных" ошибок. Отличие для клиента — только в том, что 400 не имеет смысл повторять, а 500 даёт шанс на то, что запрос таки удастся обработать.

А далее идёт по мере вашего увлечения семантикой: чем больше деталей вы сообщите клиенту, тем лучше он сможет обработать ситуацию. Тупой клиент будет трактовать любые 4xx как 400 — и ему будет достаточно.
А вот умный клиент может использовать некоторые дополнительные соглашения. 401 приглашает клиента к диалогу по выбору способа авторизации. 403 означает, что сам запрос в порядке, но прав доступа недостаточно — в клиента может быть встроена функция "обратиться к админам с запросом доступа". Кстати, в реально параноидальной системе 403 может быть запрещен как выдающий слишком много деталей неавторизованному клиенту, и вместо него лучше отдавать 404 (так, кстати, делает connect.microsoft.com).
Важно продумывать сценарии, которые вы хотите предоставить клиенту. Каждый раз, когда вы выбираете код результата, думайте о том, зачем вы возвращаете именно его.
Скажем, если вы хотите помочь клиенту выбрать время для повтора запроса, сломавшегося на сервере, можно вернуть 503 с заголовком Retry-After. Если не хотите — то клиенту всё равно, 500 или 503 вы отдали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.12 09:15
Оценка: 1 (1)
Здравствуйте, okman, Вы писали:
Раз уж вы поставили мне минус, потрачу пару минут на ответ.

O>Например, при смене транспорта не придется переделывать систему обработки ошибок.

Ну, во-первых, всё-таки придётся. Смена транспорта смене транспорта рознь. Сделать прозрачный переезд с HTTP на TCP, может, и выйдет, но никаких преимуществ транспорта вы использовать не сможете.
Совершенно неясно, стоит ли овчинка выделки.

O>Коды состояний HTTP не смогут обеспечить клиента точной информацией о том, на каком этапе обработки запроса

O>произошел сбой — на транспортном или логическом. Если, к примеру, и front end, и back end сервера могут
O>отдавать "500 Internal Server Error", то рано или поздно наступает ситуация, когда клиент получает такой
O>ответ и не знает, от кого именно он пришел и по каким правилам обрабатывать его содержимое.
Отлично. Ну, вот расскажите мне, по каким правилам нужно обрабатывать ответ 500 Internal Server Error, в зависимости от того, кто его вернул.
В моей реальности клиент видит 500, и ему всё равно, откуда он взялся.

В то же время
O>"надпротокольные" сообщения об ошибках, возвращенные с кодом 200, могут быть и более структуированными, и
O>более информативными, и вообще более соответствующими духу системы, в которой они используются.
И вот как раз это — очень плохо. Потому, что в рамках протокола вы не даёте никакой информации о семантике.
Например, прокси-сервер будет искренне полагать, что всё в порядке, и кэшировать результат такой ошибки.
Не вижу в этом никаких преимуществ.

O>Я встречал мнение, что можно использовать зарезервированные коды HTTP-состояний. Например, диапазон

O>512-599 в настоящее время свободен.
Вас обманули. Делать этого ни в коем случае не надо. Потому, что вы сочетаете недостатки обоих подходов. Неизвестные науке коды не дают использовать стандартные механизмы, разработанные для протокола HTTP, и затрудняют портирование на другой транспорт.
Нужно вкладывать "более структурированные" и "более информативные" данные внутрь протокола, выбирая код статуса сообразно семантике ответа.
Это позволяет реализовывать схемы graceful degradation — это когда нет жёсткой зависимости между реализациями клиента и сервера; в диалоге выбирается уровень "наибольшего общего кратного" и партнёры общаются на нём.
А про "соответствие духу системы", я имею ровно противоположное мнение. Либо дух системы соответствует духу HTTP, тогда грех этим не воспользоваться. Либо дух системы противоречит духу HTTP — тогда мы имеем мертворожденного мутанта, вроде SOAP, авторов которого нужно судить за преступления против технического совершенства.

O>По-моему, очень неплохая отправная точка.

Не, она слишком далеко в прошлом. В отсутствие HTTP она бы имела смысл, но теперь игнорировать RFC2616 смысла нет.
Вместо того, чтобы строить свой протокол поверх HTTP, имеет смысл просто пользоваться самим HTTP (естественно, если суть задачи этому соответствует). Зачем рожать целый новый прикладной протокол поверх существующего, когда этого существующего достаточно? Да ещё и есть встроенные возможности по расширению протокола, и опять с поддержкой graceful degradation.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.12 09:20
Оценка: 1 (1)
Здравствуйте, A13x, Вы писали:


A>Если имеются в виду SOAP-based веб-сервисы, то на мой взгляд это не очень хороший пример REST API (почему — отдельная спорная тема).

Не особо спорная. SOAP — это не REST. В самой лучшей инкарнации, SOAP — это мучительные попытки переизобрести REST, отказавшись от возможностей нижележащей архитектуры. Это как если бы кто-то взял из всего TCP только возможность отправлять пакетики размером в 1 байт в рамках каждого соединения, и построил поверх этого потоковый протокол с гарантиями доставки.
Если такое собрал ребёнок в детском саду — можно умиляться. Если это предлагает инженер — его надо уволить за профнепригодность.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.12 09:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я полностью согласен с A13x.

Да, ещё немного философии — для контекста — здесь
Автор: Sinclair
Дата: 03.04.08
.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: okman Беларусь https://searchinform.ru/
Дата: 17.10.12 12:23
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Философия: Искусственно разделять слои в приложениях не нужно.


Разделять слои в приложениях нужно не искусственно, а естественно.

S>Полное использование возможностей нижележащего протокола — вот путь к успеху. Не надо слишком думать о том, что будет, если мы заменим транспортный протокол.


Пример — веб-сервис может использовать HTTP для браузеров и бинарный протокол для других программ-клиентов.
Очевидно, что реализовать такое будет проще, если транспорт и логика протокола будут четко разделены.

O>>Коды состояний HTTP не смогут обеспечить клиента точной информацией о том, на каком этапе обработки запроса

O>>произошел сбой — на транспортном или логическом. Если, к примеру, и front end, и back end сервера могут
O>>отдавать "500 Internal Server Error", то рано или поздно наступает ситуация, когда клиент получает такой
O>>ответ и не знает, от кого именно он пришел и по каким правилам обрабатывать его содержимое.

S>Отлично. Ну, вот расскажите мне, по каким правилам нужно обрабатывать ответ 500 Internal Server Error, в зависимости от того, кто его вернул.


Вопрос не понят. При таком подходе, который я защищаю, "500 Internal Server Error" может вернуть
только фронт энд сервера. Если, копаясь в логах сервера в поисках какой-нибудь непонятной ошибки, я
нахожу код 500, то точно знаю, что до бэк энда дело вообще не дошло. И для этого мне не обязательно
вытаскивать тело ответа сообщения (которое, кстати, может быть сжато gzip-ом) или еще что-то.

S>В моей реальности клиент видит 500, и ему всё равно, откуда он взялся.


Правильно ли я понял, что в Вашей реальности несущественно, произошла ли ошибка передачи данных
или логическая ошибка самого сервиса ?

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

O>>"надпротокольные" сообщения об ошибках, возвращенные с кодом 200, могут быть и более структуированными, и

O>>более информативными, и вообще более соответствующими духу системы, в которой они используются.

S>И вот как раз это — очень плохо. Потому, что в рамках протокола вы не даёте никакой информации о семантике.


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

S>Например, прокси-сервер будет искренне полагать, что всё в порядке, и кэшировать результат такой ошибки.


Прокси может кэшировать и другие ответы. Так что данная проблема имеет малое отношение к вопросу.
Ну и есть же "pragma: no-cache".

S>Нужно вкладывать "более структурированные" и "более информативные" данные внутрь протокола,

S>выбирая код статуса сообразно семантике ответа.

Какие средства предоставляет HTTP для передачи структурированной информации об ошибке ?

S>А про "соответствие духу системы", я имею ровно противоположное мнение. Либо дух системы соответствует духу HTTP, тогда грех этим не воспользоваться. Либо дух системы противоречит духу HTTP — тогда мы имеем мертворожденного мутанта, вроде SOAP, авторов которого нужно судить за преступления против технического совершенства.


Да, судить за преступления. И уволить. А еще перед этим расстрелять.

Если надумаете ответить, напишите вот о чем — почему, когда я пытаюсь залогиниться на RSDN, используя
неправильный пароль, сервер не выкидывает мне "401 Unauthorized" или "403 Forbidden" ?
Re[4]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.12 15:44
Оценка:
Здравствуйте, okman, Вы писали:

O>Разделять слои в приложениях нужно не искусственно, а естественно.

С этим спорить я не буду, т.к. согласен. Давайте обсудим границы естественности.

O>Пример — веб-сервис может использовать HTTP для браузеров и бинарный протокол для других программ-клиентов.

Во-первых, я не вполне понимаю, что вы называете "браузерами". Вы имеете в виду JS-приложения, которые крутятся внутри браузеров и потребляют HTTP-сервисы?
Или вы говорите про пользовательское веб-приложение, которое работает на том же бэк-енде, что и веб-сервис для внешних приложений?

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

O>Вопрос не понят. При таком подходе, который я защищаю, "500 Internal Server Error" может вернуть

O>только фронт энд сервера. Если, копаясь в логах сервера в поисках какой-нибудь непонятной ошибки, я
O>нахожу код 500, то точно знаю, что до бэк энда дело вообще не дошло.
Так, давайте разберёмся. Вы — не клиент, вы разработчик. Вот разработчику конечно может быть интересно, какой именно из бесчисленных компонентов серверной стороны упал.
Но вы обещали показать какие-то отличия в логике клиента.
O>И для этого мне не обязательно вытаскивать тело ответа сообщения (которое, кстати, может быть сжато gzip-ом) или еще что-то.
Мы с вами как-то по разному понимаем процесс отладки веб-серверов. Вот вы вместо того, чтобы сравнить логи фронт-енда с логами бэк-енда, предлагаете отказаться от использования кода 500.
Зато вот отличить success response от error response от бэк-енда можно только путём вытаскивания тела сообщения (которое, кстати, может быть сжато gzip-ом). Почему вас это не смущает?

O>Правильно ли я понял, что в Вашей реальности несущественно, произошла ли ошибка передачи данных

O>или логическая ошибка самого сервиса ?
Клиенту — совершенно несущественно. В моей реальности клиент принимает только решения о том, повторять ли ему запрос, или не стоит. Если он получил 500 — это значит, что сервер не справился. Почему — это проблемы сервера.

O>Могу только прокомментировать, что системы и требования к ним бывают разные, но в тех, где мне

O>довелось поучаствовать, такое разделение практически всегда имело большой смысл.
Я буду рад, если вы объясните мне этот смысл.

O>Потому что в описываемой модели работа протокола-транспорта на данном этапе закончена — сообщение доставлено.

O>Остальным занимается прикладной протокол, расположенный выше.
Вы опять настаиваете на искусственном разделении протоколов.
O>Прокси может кэшировать и другие ответы. Так что данная проблема имеет малое отношение к вопросу.
Вопросы кэширования играют первоочередную роль в разработке распределённых сервисов.
O>Ну и есть же "pragma: no-cache".
Омг, омг. Я вижу, как вы одной рукой создаёте себе проблемы, а другой — решаете. Зачем?

O>Какие средства предоставляет HTTP для передачи структурированной информации об ошибке ?

Полные.
Статус код плюс хидеры позволяют самому тупому клиенту или прокси понять, что происходит.
Для большинства статусов (кроме нескольких особенных) можно передавать и контент. А в контенте как раз и предоставлять структурированную информацию об ошибке.

O>Да, судить за преступления. И уволить. А еще перед этим расстрелять.

Конечно.
O>Если надумаете ответить, напишите вот о чем — почему, когда я пытаюсь залогиниться на RSDN, используя
O>неправильный пароль, сервер не выкидывает мне "401 Unauthorized" или "403 Forbidden" ?
На это есть три ответа.
1. Сервер RSDN несовершенен, и не является образцом корректности.
2. Мы говорим не о веб-сервисе, а о веб-приложении. Для его клиентов наблюдаемой разницы между 400 и 200 нет.
3. Если уж быть педантом, то сервер не возвращает 401 потому, что не должен. Этот код не означает "неправильный пароль". Этот код означает "ресурс требует авторизации, а я не знаю, кто вы", и входит в специальный цикл HTTP Authentication, которая на RSDN не используется. А 403 означает, что сервер понял, кто вы, но вам туда нельзя, так что его семантика неприменима для случая неправильного пароля. Доступ до login.aspx у вас есть
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: A13x США  
Дата: 17.10.12 17:12
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, A13x, Вы писали:



A>>Если имеются в виду SOAP-based веб-сервисы, то на мой взгляд это не очень хороший пример REST API (почему — отдельная спорная тема).

S>Не особо спорная. SOAP — это не REST.

Мое отношение к SOAP так же в основном негативное, при наличии выбора я предпочту REST+JSON и т.п.

Что же касается спорности — я к тому, что тут есть почва для всякого рода разночтений и разногласий.
Навскидку по поводу дефектности связки HTTP+SOAP:
1. SOAP использует HTTP как канал доставки, SOAP может быть реализован поверх другого протокола (например JMS, SMTP).
Тут, бесспорно, можно заметить в ответ, что рассматривать HTTP как транспортный, а не прикладной протокол семантически неверно.
2. SOAP поверх HTTP можно считать частным случаем REST+XML, принимая во внимание намеренный отказ от следования рекомендациям RFC в пользу модели данных, предлагаемой SOAP-ом.
Специфичные заголовки?

However, new or experimental header fields MAY be given the semantics of request- header fields if all parties in the communication recognize them to be request-header fields. Unrecognized header fields are treated as entity-header fields.

Использование POST-only методов?
В RFC нет MUST/SHOULD требований по поводу того, что один URI на который делается POST не может выполнять несколько логически несвязанных действий, в том числе реализовывать идемпотентные операции.

Есть еще аргументы в стиле "все так делают" (поэтому можно считать это best practice) и "наработан большой опыт", но на них останавливаться не вижу смысла.
На всякий случай еще раз замечу, что лично мне SOAP не нравится по многим причинам, в основном из-за логического несоответствия протоколу (явный случай protocol misuse) и избыточности
Re[5]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: okman Беларусь https://searchinform.ru/
Дата: 17.10.12 19:17
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Так, давайте разберёмся. Вы — не клиент, вы разработчик. Вот разработчику конечно может быть интересно, какой именно из бесчисленных компонентов серверной стороны упал.

S>Но вы обещали показать какие-то отличия в логике клиента.

Например, довольно типичная ситуация — отправка на сервер неких последовательных данных, когда
важно сохранить их порядок и не потерять ни одной записи. В этом случае программа-клиент будет
повторять каждый запрос до тех пор, пока он не будет обработан сервером, и только после этого
переходить к формированию и отправке следующего. И здесь очень важно уметь определять, был ли
запрос реально обработан веб-сервисом (бэк эндом), или он "застрял" где-то на более ранних фазах.
Причем определять нужно именно программно. Еще более актуальным это становится при использовании
прокси-серверов. Вот в решении данной задачи помогает ограничение, приведенное выше — коды,
отличные от группы 200 (успех), возвращаются только фронт эндом и сигнализируют исключительно об
ошибках транспорта (в данном случае HTTP), а коды 200 означают, что запрос прошел эту стадию и
был обработан бэк эндом (хотя может иметь место ошибка на логическом уровне).

S>Вы опять настаиваете на искусственном разделении протоколов.


Во-первых, не настаиваю, а отстаиваю.
Во-вторых, критерии искусственности, пожалуйста, в студию.

O>>Прокси может кэшировать и другие ответы. Так что данная проблема имеет малое отношение к вопросу.


S>Вопросы кэширования играют первоочередную роль в разработке распределённых сервисов.


Как вопросы кэширования связаны с кодами состояний HTTP ?
Точнее, какие могут быть проблемы, если мы возвращаем 200 OK с логическим пакетом "ошибка" ?

O>>Ну и есть же "pragma: no-cache".


S>Омг, омг. Я вижу, как вы одной рукой создаёте себе проблемы, а другой — решаете. Зачем?


В чем дело ?
Вы не используете данный (или аналогичные) заголовок в своих "правильных" реализациях ?

O>>Какие средства предоставляет HTTP для передачи структурированной информации об ошибке ?


S>Полные.

S>Статус код плюс хидеры позволяют самому тупому клиенту или прокси понять, что происходит.
S>Для большинства статусов (кроме нескольких особенных) можно передавать и контент. А в контенте как раз и предоставлять структурированную информацию об ошибке.

Правильно, формат тела сообщения полностью на плечах вышележащего протокола, такого как HTML, XML или JSON.
Сам HTTP такой структурности не предоставляет, он является лишь транспортом для них, что подтверждается,
кстати, и его названием — "Hyper-Text Transfer Protocol".

O>>Если надумаете ответить, напишите вот о чем — почему, когда я пытаюсь залогиниться на RSDN, используя

O>>неправильный пароль, сервер не выкидывает мне "401 Unauthorized" или "403 Forbidden" ?
S>На это есть три ответа.
S>1. Сервер RSDN несовершенен, и не является образцом корректности.
S>2. Мы говорим не о веб-сервисе, а о веб-приложении. Для его клиентов наблюдаемой разницы между 400 и 200 нет.
S>3. Если уж быть педантом, то сервер не возвращает 401 потому, что не должен. Этот код не означает "неправильный пароль". Этот код означает "ресурс требует авторизации, а я не знаю, кто вы", и входит в специальный цикл HTTP Authentication, которая на RSDN не используется. А 403 означает, что сервер понял, кто вы, но вам туда нельзя, так что его семантика неприменима для случая неправильного пароля. Доступ до login.aspx у вас есть

Да, но ведь по Вашей "легенде" коды 401 или 403 (или другие) могли бы использоваться бэк эндом
сайта для "своих" логических ошибок, типа ошибки логина ? Выглядит как противоречие.
Re[6]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.10.12 11:13
Оценка:
Здравствуйте, okman, Вы писали:


O>Например, довольно типичная ситуация — отправка на сервер неких последовательных данных, когда

O>важно сохранить их порядок и не потерять ни одной записи. В этом случае программа-клиент будет
O>повторять каждый запрос до тех пор, пока он не будет обработан сервером, и только после этого
O>переходить к формированию и отправке следующего. И здесь очень важно уметь определять, был ли
O>запрос реально обработан веб-сервисом (бэк эндом), или он "застрял" где-то на более ранних фазах.
O>Причем определять нужно именно программно. Еще более актуальным это становится при использовании
O>прокси-серверов. Вот в решении данной задачи помогает ограничение, приведенное выше — коды,
O>отличные от группы 200 (успех), возвращаются только фронт эндом и сигнализируют исключительно об
O>ошибках транспорта (в данном случае HTTP), а коды 200 означают, что запрос прошел эту стадию и
O>был обработан бэк эндом (хотя может иметь место ошибка на логическом уровне).
Прекрасно, просто прекрасно. Вы приводите ровно те примеры, где REST в целом и HTTP в частности на ошмётки порвут любой альтернативный протокол.
Итак, клиент наблюдает код 500. Что он, в вашем примере, означает?
Я лично вижу три варианта:
1. Фронт-енд не смог связаться с бэк-ендом
2. Фронт-енд связался с бэк-ендом, но в процессе обработки записи возникла "логическая ошибка", транзакция была откачена
3. Фронт-енд связался с бэк-ендом, бэк-енд всё обработал, но в момент отдачи результата во фронт-енд упал канал.
Вы предлагаете елиминировать №2, возвращая в таких случаях 200.
Но это вам ничем не поможет — вы всё ещё не можете отличить №1 от №3.
Это потому, что вы плохо спроектировали протокол взаимодействия. Дело даже не в HTTP, а в отсутствии понятия идемпотентности в вашем протоколе.
Правильное решение — сделать операцию "обработать запись" идемпотентной. В терминах протокола HTTP это было бы выполнение глагола PUT на адрес нужного вам элемента.
Клиент трактует коды следующим образом:
1хх — мы игнорируем пока, поскольку схема 100 continue нас не особо пока интересует
2xx — всё получилось, можно посылать следующий
3хх — нужно скорректировать свои действия соотвествующим образом и попробовать снова (см. семантику 301, 302, и 307)
4хх — придётся скорректировать свои действия (например, вступить в цикл HTTP Authentication), либо отрапортовать ошибку
5xx — нужно выполнять повторный запрос в соответствии с настройками клиента и рекомендациями сервера.
Ошибки других типов (TCP connection lost и прочее) трактуются так же, как 5хх.

Всё. Не надо никаких больше гаданий, на каком там этапе "застрял" запрос.
Если вдруг оказалось, что запрос был успешен, просто клиент об этом так и не узнал по какой-то причине, сервер молча примет запрос и вернёт 2xx.

O>Во-вторых, критерии искусственности, пожалуйста, в студию.

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

O>Как вопросы кэширования связаны с кодами состояний HTTP ?

Напрямую. Может быть, настало время прочесть таки RFC 2616? Каждый код состояния имеет определённую семантику. Полное описание как-то выходит за рамки форумного поста.
O>Точнее, какие могут быть проблемы, если мы возвращаем 200 OK с логическим пакетом "ошибка" ?
Очень простые: никакие из стандартных инструментов не считают этот логический пакет ошибкой.

O>В чем дело ?

O>Вы не используете данный (или аналогичные) заголовок в своих "правильных" реализациях ?
Как правило — нет. Если вам потребовалась pragma:no-cache, то как правило, это означает, что вы делаете что-то неправильно.
В HTTP из коробки работают вполне разумные правила кэширования. Прагма позволяет отключить их и нужна, скажем, если вы внезапно решили изменить семантику глагола GET, сделав его небезопасным. Вот как раз так делать не надо.

O>>>Какие средства предоставляет HTTP для передачи структурированной информации об ошибке ?


O>Да, но ведь по Вашей "легенде" коды 401 или 403 (или другие) могли бы использоваться бэк эндом

O>сайта для "своих" логических ошибок, типа ошибки логина ? Выглядит как противоречие.
Нет, не выглядит. "Свои" логические ошибки могут вкладываться в существующие статусы HTTP, уточняя их.
А вы предлагаете их переопределить, т.е. дать им семантику, противоречащую стандартной семантике.
Посмотрите на так называемые substatus codes в IIS: там 20 разных вариантов 403.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.10.12 11:22
Оценка:
Здравствуйте, A13x, Вы писали:

A>1. SOAP использует HTTP как канал доставки, SOAP может быть реализован поверх другого протокола (например JMS, SMTP).

A>Тут, бесспорно, можно заметить в ответ, что рассматривать HTTP как транспортный, а не прикладной протокол семантически неверно.
Насчёт семантики — я не против такого использования. Кто ж спорит, можно и на бентли цемент возить.
Раздражает исключительно неэффективность связки этих двух протоколов.
Хотя в современном мире такие решения считаются нормой: лично наблюдал конструкции, которые сам SOAP используют в качестве транспортного протокола, выставляя ровно один метод ProcessMessage(), в который отправляется полувалидный XML с указанием того, что именно следует сделать. Увы, уголовной ответственности за такое не предусмотрено ни в одной стране мира.

A>2. SOAP поверх HTTP можно считать частным случаем REST+XML, принимая во внимание намеренный отказ от следования рекомендациям RFC в пользу модели данных, предлагаемой SOAP-ом.

Лично мне это мешает сделать отсутствие внятных способов декларировать семантику SOAP — сообщений. Может я чего пропустил, но я не помню изкоробочного способа пометить сообщение как safe или idempotent.

A>Специфичные заголовки?

A>

A>However, new or experimental header fields MAY be given the semantics of request- header fields if all parties in the communication recognize them to be request-header fields. Unrecognized header fields are treated as entity-header fields.

A>Использование POST-only методов?
A>В RFC нет MUST/SHOULD требований по поводу того, что один URI на который делается POST не может выполнять несколько логически несвязанных действий, в том числе реализовывать идемпотентные операции.
Это понятно, что не обязан. Просто это выглядит как некоторый идиотизм. "Вот я имею safe операцию GetStockQuotes(), но я вам об этом не скажу, поэтому вы будете реально нагружать сервер каждый раз, как клиент захочет проверить обновления"

A>Есть еще аргументы в стиле "все так делают" (поэтому можно считать это best practice) и "наработан большой опыт", но на них останавливаться не вижу смысла.

О да. Я перестал рассматривать эти аргументы много лет назад — уж очень много в индустрии заблуждений, носящих маниакально-массовый характер. Диссертация по REST вышла 12 лет тому, и до сих пор мало кто знает, что это такое.
A>На всякий случай еще раз замечу, что лично мне SOAP не нравится по многим причинам, в основном из-за логического несоответствия протоколу (явный случай protocol misuse) и избыточности
Ага.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: anonymous Россия http://denis.ibaev.name/
Дата: 18.10.12 13:21
Оценка:
Здравствуйте, A13x, Вы писали:

A>Из REST API Design Guide:


RFC 2616 говорит:

10.4.1 400 Bad Request
The request could not be understood by the server due to malformed syntax.


Сомневаюсь, что неверные параметры тянут на синтаксическую ошибку.
Re[7]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.12 17:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

O>>Например, довольно типичная ситуация — отправка на сервер неких последовательных данных, когда

O>>важно сохранить их порядок и не потерять ни одной записи.

S>Прекрасно, просто прекрасно. Вы приводите ровно те примеры, где REST в целом и HTTP в частности на ошмётки порвут любой альтернативный протокол.

S>Итак, клиент наблюдает код 500. Что он, в вашем примере, означает?

Только одно — запрос следует повторить позже.

S>Я лично вижу три варианта:

S>1. Фронт-енд не смог связаться с бэк-ендом
S>2. Фронт-енд связался с бэк-ендом, но в процессе обработки записи возникла "логическая ошибка", транзакция была откачена
S>3. Фронт-енд связался с бэк-ендом, бэк-енд всё обработал, но в момент отдачи результата во фронт-енд упал канал.
S>Вы предлагаете елиминировать №2, возвращая в таких случаях 200.
S>Но это вам ничем не поможет — вы всё ещё не можете отличить №1 от №3.

Это никак не связано с тем, что я возвращаю код 200 на логическую ошибку, а не какой-нибудь 400.

S>Это потому, что вы плохо спроектировали протокол взаимодействия. Дело даже не в HTTP, а в отсутствии понятия идемпотентности в вашем протоколе.


Фантазии. Мы здесь обсуждаем разумность возврата кода 200 на логические ошибки или что-то другое ?

S>Клиент трактует коды следующим образом:

S>1хх — мы игнорируем пока, поскольку схема 100 continue нас не особо пока интересует
S>2xx — всё получилось, можно посылать следующий
S>3хх — нужно скорректировать свои действия соотвествующим образом и попробовать снова (см. семантику 301, 302, и 307)
S>4хх — придётся скорректировать свои действия (например, вступить в цикл HTTP Authentication), либо отрапортовать ошибку

Стоп.
Если 4xx будет использоваться для сигнализации о логических ошибках, клиенту придется выполнять дополнительную
работу, чтобы отличать один тип ошибок от другого. Особенно если логические ошибки будут разделять с HTTP одни и
те же коды состояний. Я предлагаю избавить клиента от этой обязанности и вообще не завязываться слишком на
нижележащий протокол (в данном случае HTTP). Причины описаны выше, повторять их не вижу смысла.

S>Искусственность — это когда вы пытаетесь изолировать один уровень от существенных подробностей другого уровня.

S>Например, когда вы делаете вид, что сетевой латентности и ограничений ширины полосы не существует, и не даёте возможности контролировать кэширование.

Сетевая латентность и ширина полосы, говорите ? Какое отношение это имеет к HTTP ?
И где я "делал вид" — можно цитату ?

Существенные подробности или несущественные — это решать не нам, все зависит от конкретных задач и перспектив.
Где-то разделение будет искусственным, где-то естественным. IMHO при выборе лучше опираться на конкретные
соображения, а не слепо доверять чужому опыту или книжным рекомендациям. Топикстартер свой выбор сделал.

S>Напрямую. Может быть, настало время прочесть таки RFC 2616? Каждый код состояния имеет определённую семантику. Полное описание как-то выходит за рамки форумного поста.


Половина серверов в интернете плевать хотела на RFC. Это я Вам как практик говорю.

O>>Точнее, какие могут быть проблемы, если мы возвращаем 200 OK с логическим пакетом "ошибка" ?


S>Очень простые: никакие из стандартных инструментов не считают этот логический пакет ошибкой.


Так какие конкретно могут быть проблемы, я так и не понял.

O>>В чем дело ?

O>>Вы не используете данный (или аналогичные) заголовок в своих "правильных" реализациях ?

S>Как правило — нет. Если вам потребовалась pragma:no-cache, то как правило, это означает, что вы делаете что-то неправильно.

S>В HTTP из коробки работают вполне разумные правила кэширования. Прагма позволяет отключить их и нужна, скажем, если вы внезапно решили изменить семантику глагола GET, сделав его небезопасным. Вот как раз так делать не надо.

Что интересно, я тоже практически никогда не испытываю необходимости в "pragma: no-cache".
Может, потому что я не изменяю семантику GET ?

O>>Да, но ведь по Вашей "легенде" коды 401 или 403 (или другие) могли бы использоваться бэк эндом

O>>сайта для "своих" логических ошибок, типа ошибки логина ? Выглядит как противоречие.

S>Нет, не выглядит. "Свои" логические ошибки могут вкладываться в существующие статусы HTTP, уточняя их.

S>А вы предлагаете их переопределить, т.е. дать им семантику, противоречащую стандартной семантике.

Вы не сможете "приклеить" мне какие-то противоречия, потому что встроенная семантика состояний HTTP
гораздо прозрачнее и недвусмысленнее тех дрязг между клиентом и сервером, которые мы сейчас обсуждаем:

RFC 2616

10.2.1 200 OK

The request has succeeded. The information returned with the response
is dependent on the method used in the request, for example:

GET an entity corresponding to the requested resource is sent in
the response;

HEAD the entity-header fields corresponding to the requested
resource are sent in the response without any message-body;

POST an entity describing or containing the result of the action;

"The request has succeeded". Все, вот и вся семантика.
Re[8]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.10.12 03:56
Оценка:
Здравствуйте, okman, Вы писали:

O>Только одно — запрос следует повторить позже.

Отлично. В моём примере всё точно так же.

O>Это никак не связано с тем, что я возвращаю код 200 на логическую ошибку, а не какой-нибудь 400.

O>Фантазии. Мы здесь обсуждаем разумность возврата кода 200 на логические ошибки или что-то другое ?
А, я-то думал, что вы против возврата 500.



O>Стоп.

O>Если 4xx будет использоваться для сигнализации о логических ошибках, клиенту придется выполнять дополнительную
O>работу, чтобы отличать один тип ошибок от другого. Особенно если логические ошибки будут разделять с HTTP одни и
O>те же коды состояний. Я предлагаю избавить клиента от этой обязанности и вообще не завязываться слишком на
O>нижележащий протокол (в данном случае HTTP). Причины описаны выше, повторять их не вижу смысла.
Простите, но клиенту в любом случае придётся выполнять дополнительную работу, чтобы отличить один тип ошибок от другого. Вы просто усложняете схему, заставляя его анализировать 403 Access Denied и 200 Ok Access Denied.
Впрочем, тупой клиент и не должен этого делать — ему достаточно первой цифры, чтобы понять, что это он что-то сделал не так, а не сервер. В тупом случае клиент просто пишет в лог отрицательный результат и успокаивается до прихода пользователя, который достаточно умён, чтобы принять решение.

O>Сетевая латентность и ширина полосы, говорите ? Какое отношение это имеет к HTTP ?

Как это какое? Самое прямое. Вот, например, для экономии ширины полосы в HTTP встроено понятие content encoding negotiation. Благодаря которому в нём из коробки работает gzip-компрессия.
А для учёта латентности есть понятие conditional GET, которое позволяет избежать лишнего запроса "изменились ли данные с прошлого обращения".
А все RCP-style протоколы стараются максимально замазать эти подробности, делая локальный и удалённый вызовы максимально неразличимыми.

O>И где я "делал вид" — можно цитату ?

Ну вы же хотите абстрагироваться от подробностей протокола. А эти подробности и есть работа с шириной полосы и латентностью.

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

O>соображения, а не слепо доверять чужому опыту или книжным рекомендациям. Топикстартер свой выбор сделал.

O>Половина серверов в интернете плевать хотела на RFC. Это я Вам как практик говорю.

И вы считаете это достаточной причиной для того, чтобы тоже его игнорировать?

O>Так какие конкретно могут быть проблемы, я так и не понял.

Неразрешимых проблем, конечно же, нет. Но вы только что считали проблемой то, что по HTTP логу вы не видите с первого взгляда, где была ошибка — на front-end или на back-end. А теперь вы внезапно не считаете проблемой то, что во HTTP логу вообще не видно, ошибка ли произошла, или достигнут успех.

O>>>В чем дело ?

O>>>Вы не используете данный (или аналогичные) заголовок в своих "правильных" реализациях ?

O>Что интересно, я тоже практически никогда не испытываю необходимости в "pragma: no-cache".

O>Может, потому что я не изменяю семантику GET ?
Я понятия не имею, что именно вы делаете. Но ваше нежелание пользоваться протоколом HTTP как-то настораживает.
Если вы опишете подробнее, что именно вы делаете, я смогу сказать, что именно вы делаете неправильно.

O>"The request has succeeded". Все, вот и вся семантика.

Правильно. Но в вашем случае он вовсе не succeeded.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: okman Беларусь https://searchinform.ru/
Дата: 19.10.12 06:08
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А, я-то думал, что вы против возврата 500.


Я против ситуации, когда 500 может возвращаться кем-то еще, кроме серверного фронт энда.

S>Простите, но клиенту в любом случае придётся выполнять дополнительную работу, чтобы отличить один тип ошибок от другого. Вы просто усложняете схему, заставляя его анализировать 403 Access Denied и 200 Ok Access Denied.


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

O>>Сетевая латентность и ширина полосы, говорите ? Какое отношение это имеет к HTTP ?

S>Как это какое? Самое прямое. Вот, например, для экономии ширины полосы в HTTP встроено понятие content encoding negotiation. Благодаря которому в нём из коробки работает gzip-компрессия.
S>А для учёта латентности есть понятие conditional GET, которое позволяет избежать лишнего запроса "изменились ли данные с прошлого обращения".

S>Ну вы же хотите абстрагироваться от подробностей протокола. А эти подробности и есть работа с шириной полосы и латентностью.


Пардон, был не точен.
Вопрос должен был звучать так: какое отношение имеют латентность и ширина полосы к данным, которые,
собственно, передаются через HTTP ? Например, взять тот же HTML. В нем нет никакого намека на связь с
HTTP (если не считать <meta http-equiv>), на опции сжатия и прочие детали. Именно поэтому HTML не
зависит от транспорта, HTML-страницу можно сохранять в файл, а не только передавать по сети, и т.д.
Точно также, с обратной стороны, сам HTTP не накладывает каких-либо ограничений на передаваемые данные и
его спецификация определяет набор лишь самых базовых семантик, а все остальное перекладывается на
"совесть" прикладного протокола поверх него. И это, по моему мнению, огромный плюс. А когда разработчики
смешивают логику своих веб-сервисов с работой транспорта, они рискуют свести этот плюс на нет.
При этом я признаю, что изоляция уровней в определенных случаях лишена смысла или избыточна.

O>>Половина серверов в интернете плевать хотела на RFC. Это я Вам как практик говорю.


S>И вы считаете это достаточной причиной для того, чтобы тоже его игнорировать?


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

O>>Так какие конкретно могут быть проблемы, я так и не понял.


S>Неразрешимых проблем, конечно же, нет. Но вы только что считали проблемой то, что по HTTP логу вы не видите с первого взгляда, где была ошибка — на front-end или на back-end. А теперь вы внезапно не считаете проблемой то, что во HTTP логу вообще не видно, ошибка ли произошла, или достигнут успех.


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

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


Спасибо, но не стоит.

O>>"The request has succeeded". Все, вот и вся семантика.


S>Правильно. Но в вашем случае он вовсе не succeeded.


Об этом можно спорить до бесконечности. У меня желания нет. А у Вас ?
Re[9]: Может ли веб-приложение возвращать 400 Bad Request при некорректных парам
От: Geri Россия http://web-notes.ru/
Дата: 19.10.12 06:09
Оценка: 103 (2)
Мне приятно, что поднятая мною тема стала предметом активного обсуждения, но в то же время мне несколько неудобно из-за того, что я сам несколько выпал из своей же темы. Я получаю по почте новые сообщения и внимательно их читаю. Я перестал сюда писать, т.к. лично для себя я давно всё решил. Моя позиция полностью совпадает с позициями A13x и Sinclair, они изложены настолько хорошо, что мне к ним нечего ни добавить, ни убавить. И, чтоб хоть как-то проявить своё участие в своей теме я попытаюсь подвести некоторый промежуточный итог дискуссии, расставить точки над i, и попытаюсь привести может быть какие-то новые аргументы, которые повлияют на мнение okman.

На мой взгляд, основным камнем преткновения является то, что по мнению okman HTTP является чисто транспортным протоколом, что по его мнению подтверждается словом "Transport" в расшифровке его аббревиатуры, и поэтому использовать его нужно чисто как способ доставки сообщений и не более того, а всю семантику реализовывать через какие-то прикладные протоколы высшего уровня. По мнениям A13x, Sinclair и моему HTTP хоть и является транспортным, но является в то же время и прикладным протоколом тоже, что подтверждается здравым смыслом и русскоязычной Википедией, которая определяет его как "протокол прикладного уровня передачи данных". Следуя принципу Бритвы Оккама, мы не должны плодить новые сущности сверх необходимого. Под новыми сущностями в данном случае я имею в виду новые прикладные протоколы, а должны стараться по максимуму использовать уже существующие.

У HTTP есть очень много возможностей, которые покрывают практически весь спектр потребностей веб-разработчиков. Причем как разработчиков сайтов для людей, так и разработчиков веб-сервисов для взаимодействия типа "компьютер-компьютер". Расширенное описание ошибки всегда можно передать в теле ответа в том формате, который понимает клиент. При этом необязательно даже использовать отдельные URL'ы для людей и машин, можно использовать встроенный в HTTP механизм Content Negotiation. Если клиент прислал нам в запросе заголовок Accept, где на первом месте text/html, значит перед нами человек и ему можно рассказать об ошибке литературным языком, за одно при помощи Accept-Language можно автоматически выбрать язык, который для этого человека наиболее предпочтителен. Если же нам прислали Accept: application/xml, то мы понимаем, что перед нами робот, и отвечаем ему структурированным описанием результата на XML (аналогично для JSON). Здесь не нужно придумывать никаких своих высокоуровневых протоколов.

Безусловно, мы можем создавать протоколы на подобии SOAP, которые игнорируют прикладные возможности HTTP, используя для передачи состояний свои собственные структурированные ответы (хотя даже SOAP в случае ошибки возвращает клиенту не 200, а 500 и XML-ку с описанием ошибки в теле ответа), но если мы хотим, чтобы наш веб-сервис был популярным, мы должны по максимуму использовать graceful degradation, чтобы в каких-то простых юзкейсах пользователи могли использовать примитивные HTTP клиенты и писать "батники" на основе HTTP-кодов, возвращаемых wget'ом или curl'ом, использовать grep и т.п. Эта возможность использовать простые методы для простых задач обеспечит успех нашему внешнему API.

Разделение реализации веб-приложения на frontend и backend несущественно для пользователя -- это личное дело разработчика как он реализует внутреннюю архитектуру. Но его внутренняя архитектура не должна определять способ внешнего взаимодействия. В идеале мы сначала пишем документацию на API типа: отправляешь такой-то запрос, получаешь такой-то ответ, если произошла такая-то ошибка, то ответ будет выглядеть так, если другая, то вот так. При этом API должно быть максимально простое и должно учитывать только потребности клиента, чтобы быть ему максимально удобным и полезным. А уже потом разработчик веб-сервиса должен спроектировать свою внутреннюю архитектуру так, чтобы реализовывать описанный в документации функционал. Если его разделение приложения на слои выражается в невозможности реализовать некоторый спроектированный функционал, значит выбранная архитектура неудачна. API должен быть более статичен, чем частная реализация. Однажды может потребоваться переписать реализацию на другом фреймворке или на другом языке, при этом для пользователя ничего не должно поменяться. Влияние архитектурных особенностей системы на внешний API может проявляться только в вопросах оптимизации быстродействия.

Хотя, если смотреть на проблему в философском ключе, то можно говорить о том, что мы создаем новый высокоуровневый протокол поверх HTTP даже когда делаем обычный сайт для веб-браузеров. Одной из сторон данного высокоуровнего протокола является человек, который принимает информацию в виде букв и знаков на понятном ему языке, отформатированных и скомпонованных принятым способом, а общается он с сервером при помощи кликов мыши и букв, набираемых с клавиатуры. Расположение ссылок меню и правила заполнения форм -- это своего рода протокол, который интуитивно понятен пользователю. Пусть не сразу, но через некоторое время наверняка. А при разработке внешнего API высокоуровневый протокол заключается в соглашении о том, на какие адреса какие запросы с какими параметрами надо слать, чтобы получить тот или иной желаемый результат. Можно ли считать документацию на API описанием высокоуровневого прикладного протокола? Думаю, да, можно.

Вообще, начиналось всё с моего вопроса о том, справедливо ли скрипту возвращать 400 Bad Request в ответ на запрос с отсутствующими или неправильными обязательными параметрами. Меня, как и многих, смущало то, что код 400 должен возвращаться в ответ на ошибку синтаксиса, из-за которой запрос не может быть понят сервером. Из языков программирования ошибка синтаксиса -- это что-то очень формальное типа пропущенной точки с запятой, недопустимый символ в имени переменной, не закрыта скобка. Но если прочитать определение слова синтаксис, то начинаешь смотреть на проблему шире. В естественных языках синтаксис отвечает за правильный порядок слов в предложениях, согласованность окончаний (падеж, род, число, время и т.п.). Если вы в поле для ввода сообщения на этом форуме ввели текст, который не подчеркнула встроенная проверка орфографии, это ещё не значит, что у вас нет ошибок синтаксиса.

Параметры в HTTP являются частью запроса и они должны быть так же согласованы и непротиворечивы, как заголовки запроса (как слова в предложениях). Они могут быть верными "орфографически", но не согласованы между собой. Поэтому несогласованность или отсутствие необходимых параметров, я думаю, можно считать ошибкой синтаксиса, а не логики. Хотя, границы иногда могут быть весьма размыты. Одно дело, когда обязательный параметр отсутствует или имеет заведомо неправильное значение (например, ожидалось число, пришла строка) -- это 100% синтаксис. Но как быть, если формат значения правильный, но значение неправильное? Например, как у Facebook'а в его Graph API -- он возвращает 400 если мы передали ему устаревший access_token. Он вообще передает код 400 на любую ошибку, кроме случаев, когда у них произошел какой-то серьёзный сбой (но я такого ещё не видел).
-- С уважением, Павел Мелехов, Екатеринбург.
Re[10]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Geri Россия http://web-notes.ru/
Дата: 19.10.12 06:28
Оценка:
Здравствуйте, okman, Вы писали:

S>>А, я-то думал, что вы против возврата 500.

O>Я против ситуации, когда 500 может возвращаться кем-то еще, кроме серверного фронт энда.

Я не очень понимаю что вы имеете в виду, когда говорите о фронтэнде и бэкэнде. Судя по гуглу, примерно половина программистов рунета путают понятия backend и back-office, называя бэкэндом админку сайта. Но вы вроде бы не из этих. В моём представлении бэкэндом можно считать, например, серверную часть в приложениях типа клиент-сервер (например, ajax), в традиционных веб-приложениях без ajax бэкэндом можно считать базу данных, классы моделей и все прочие классы, кроме контроллеров и шаблонов. Но представлять это можно по-разному, суть от этого не поменяется. Поэтому мне бы и хотелось понять какое значение вкладываете вы и почему это бэкэнд не может возвращать статус 500. Вот, база данных у вас это фронтэнд или бэкэнд? По мне так это стопроцентный бэкэнд. Ошибка подключения к базе данных или ошибка SQL приведет к возврату какого статуса HTTP клиенту? 5xx или 4xx? Я думаю после вашего ответа на этот вопрос многое должно проясниться.
-- С уважением, Павел Мелехов, Екатеринбург.
Re[10]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.10.12 07:55
Оценка:
Здравствуйте, okman, Вы писали:

O>Я против ситуации, когда 500 может возвращаться кем-то еще, кроме серверного фронт энда.

Я уже пояснил вам, почему это не имеет смысла.

O>В описанном примере клиенту ничего анализировать как раз и не нужно.

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

O>Пардон, был не точен.

O>Вопрос должен был звучать так: какое отношение имеют латентность и ширина полосы к данным, которые,
O>собственно, передаются через HTTP ? Например, взять тот же HTML. В нем нет никакого намека на связь с
O>HTTP (если не считать <meta http-equiv>), на опции сжатия и прочие детали. Именно поэтому HTML не
O>зависит от транспорта, HTML-страницу можно сохранять в файл, а не только передавать по сети, и т.д.
Ну, во-первых, вы лукавите. Попробуйте указать адрес страницы на диске в качестве атрибута action тега form.
Так что HTML — даже сам по себе — вполне себе тесно связан с HTTP.
Во-вторых, HTML — это не протокол. Это всего лишь один из форматов данных. Когда мы проектируем приложение, мы не только придумываем формат данных, мы определяем протокол — то есть соглашение, на основе которого клиентская часть взаимодействует с серверной. И вот как раз здесь — в протоколе — нам важно учитывать особенности среды, в частности полосу и латентность.
В-третьих, отношение латентности и ширины полосы к данным, передаваемым по HTTP, может быть и прямым — в протокол встроена возможность договориться о получении частичных данных. И если Accept-Ranges: bytes применимо к любому content-type, то специфические units, выбранные для вашего прикладного протокола, потребуют и специфического контента.
Ну, то есть если вы отдаёте, скажем, какой-то список, и хотите дать клиенту возможность получать его по частям, то вы можете отдать Accept-Ranges: items, и принимать Range: items=500-599 в Get-запросах.
Понятно, что это потребует определённого формата и от передаваемых данных.

O>Точно также, с обратной стороны, сам HTTP не накладывает каких-либо ограничений на передаваемые данные и

O>его спецификация определяет набор лишь самых базовых семантик, а все остальное перекладывается на
O>"совесть" прикладного протокола поверх него. И это, по моему мнению, огромный плюс. А когда разработчики
O>смешивают логику своих веб-сервисов с работой транспорта, они рискуют свести этот плюс на нет.
O>При этом я признаю, что изоляция уровней в определенных случаях лишена смысла или избыточна.
Не очень понятно, что вы имеете в виду под "прикладным протоколом поверх него".
Я знаю два способа построить прикладной протокол поверх HTTP:
1. Сделать вид, что HTTP — это такой UDP с более пушистой адресацией енд-поинтов и синхрнонными ответами. Игнорировать глаголы, статусы, кэширование, докачку, компрессию, шифрование, и прочие интересные вещи. Всё, что из потребуется, строить с нуля, игнорируя инфраструктуру.
2. Использовать HTTP "как есть", потому что в нём из коробки есть почти всё, что может потребоваться современному клиент-серверному протоколу, и ещё 100500 вещей, о которых велосипедостроителей задуматься даже не успел.
В тех редких случаях, когда семантики изкоробочного RFC 2616 недостаточно, пользоваться заложенными заранее точками расширения.

По ряду признаков мне кажется, что вы предпочитаете способ №1.

O>Об игнорировании речь не шла. Но проектировать веб-компоненты нужно с учетом поведения существующих

O>реализаций, которые, как показывает практика, могут вести себя некорректно. Даже если мы пишем
O>"правильного" клиента, который работает с "правильным" сервером, в игру может вклиниться чужой
O>прокси-сервер со своими собственными правилами. К сожалению. Не учитывать этого — значит писать
O>"тепличный" софт, который будет работать только в ограниченном диапазоне условий.
Золотые слова. Вот как раз пытаться "прогнуть" HTTP, отдавая, скажем, 200 Ok вместо ошибки — это прямой способ нарваться на прокси, который посчитает себя умнее вас, и проигнорирует модные хидеры, которыми вы пытаетесь его контролировать.

O>Все верно, в том примере, который я приводил (последовательная отправка данных), клиенту не

O>обязательно отличать логическую ошибку от логического успеха. Но важно отличать логическую ошибку от
O>ошибки транспорта, чтобы выяснить, нужно ли пытаться повторить запрос (возможно, со скорректированными
O>параметрами) или перейти к следующему. Для этого достаточно иметь код состояния HTTP.
Ок, тогда я не понял, что вы называете "логической ошибкой", а что — "ошибкой транспорта".
Вот у нас на бэк-енде вылетел StackOverflowException. Какой код вы предлагаете возвращать в таком случае?

O>Об этом можно спорить до бесконечности. У меня желания нет. А у Вас ?

Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: okman Беларусь https://searchinform.ru/
Дата: 19.10.12 09:48
Оценка:
Здравствуйте, Sinclair, Вы писали:

O>>Я против ситуации, когда 500 может возвращаться кем-то еще, кроме серверного фронт энда.


S>Я уже пояснил вам, почему это не имеет смысла.


В рассмотренном примере этот факт не имеет значения.

O>>В описанном примере клиенту ничего анализировать как раз и не нужно.

O>>4xx — ошибка формирования запроса. 2xx — запрос доставлен, можно переходить к следующему.

S>Погодите. Вы же говорите, что к следующему можно переходить, только если сервер его принял.


2xx — запрос обработан бэк эндом. Клиент переходит к формированию и отправке следующего.
4xx может означать только некорректно сформированные на уровне HTTP данные.
5xx — сервер недоступен, запрос следует повторить позже.
Все ясно, как день.

S>Ну, во-первых, вы лукавите. Попробуйте указать адрес страницы на диске в качестве атрибута action тега form.

S>Так что HTML — даже сам по себе — вполне себе тесно связан с HTTP.

Это один из его недостатков. Такой же, как http-equiv в элементе meta.

S>Во-вторых, HTML — это не протокол. Это всего лишь один из форматов данных. Когда мы проектируем приложение, мы не только придумываем формат данных, мы определяем протокол — то есть соглашение, на основе которого клиентская часть взаимодействует с серверной. И вот как раз здесь — в протоколе — нам важно учитывать особенности среды, в частности полосу и латентность.


Да, все верно. На уровне HTTP мы используем сжатие, кэширование, даже контроль целостности.
А уровень данных играет по своим правилам. Я лишь предлагаю не смешивать их воедино, а
аккуратно изолировать друг от друга. При этом разница насколько тонкая, что остается
почти незаметной. Фактически, все различия сводятся только к тому, чтобы не использовать на
уровне данных (HTML/JSON/XML/другое) механизмы из нижележащего уровня (HTTP/TCP/UDP/другое),
такие как коды состояний или опции сжатия, а оставить их на совести того самого уровня, который ниже.
Впечатление, будто я призываю отказываться от встроенных механизмов HTTP — в корне неверное.

S>Не очень понятно, что вы имеете в виду под "прикладным протоколом поверх него".

S>Я знаю два способа построить прикладной протокол поверх HTTP:
S>1. Сделать вид, что HTTP — это такой UDP с более пушистой адресацией енд-поинтов и синхрнонными ответами. Игнорировать глаголы, статусы, кэширование, докачку, компрессию, шифрование, и прочие интересные вещи. Всё, что из потребуется, строить с нуля, игнорируя инфраструктуру.
S>2. Использовать HTTP "как есть", потому что в нём из коробки есть почти всё, что может потребоваться современному клиент-серверному протоколу, и ещё 100500 вещей, о которых велосипедостроителей задуматься даже не успел.
S>В тех редких случаях, когда семантики изкоробочного RFC 2616 недостаточно, пользоваться заложенными заранее точками расширения.

S>По ряду признаков мне кажется, что вы предпочитаете способ №1.


Это вовсе не так. Прокомментировал выше.

S>Вот как раз пытаться "прогнуть" HTTP, отдавая, скажем, 200 Ok вместо ошибки — это прямой способ нарваться на прокси, который посчитает себя умнее вас, и проигнорирует модные хидеры, которыми вы пытаетесь его контролировать.


Давайте рассмотрим еще один (очень упрощенный) пример.
Допустим, есть веб-сервис покупок, через который я POST-запросом могу заказать себе, скажем,
ящик водки. При успешном заказе сервер возвращает 200 OK, а с моего счета списывается некая сумма.
В определенный момент мой баланс становится нулевым и денег на водку не хватает — на очередной
запрос сервер должен возвратить что ? "200 OK" или "400 Bad Request" ? Допустим, первый вариант.
Объясните, почему прокси вдруг должен закэшировать ответы с кодом 200, но при этом передавать
ответы с кодом 400 мимо кэша ? Требование идемпотентности к запросам POST не предъявляется.
А по поводу кода 400 в RFC 2616 сказано: "The client SHOULD NOT repeat the request without
modifications" — клиенту не рекомендуется повторять тот же самый запрос, не включив в него
модификации. Как раз в этом случае прокси с большей вероятностью закэширует ответ-400 на
один и тот же запрос и будет все время его возвращать.

У нас разное понимание семантики кода 200.
Я считаю, что код 200 — это "запрос обработан". Или, точнее говоря, "сообщение доставлено".
Что это за запрос и что это за сообщение — уже не забота HTTP.

S>Ок, тогда я не понял, что вы называете "логической ошибкой", а что — "ошибкой транспорта".


Ошибка транспорта — это когда в GET-запросе не указывается URL или Host.
Логическая ошибка — это когда я пытаюсь заказать водку, а денег на счету нет.

S>Вот у нас на бэк-енде вылетел StackOverflowException. Какой код вы предлагаете возвращать в таком случае?


Код из группы 500, понятное дело. Запрос не был обработан бэк эндом, для клиента
это достаточная для принятия нужного решения информация.
Re[12]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Geri Россия http://web-notes.ru/
Дата: 19.10.12 10:24
Оценка:
Здравствуйте, okman, Вы писали:

O>2xx — запрос обработан бэк эндом. Клиент переходит к формированию и отправке следующего.


А почему запрос непременно должен быть обработан бэкэндом? Может нам в каком-то запросе не нужна ни база данных, ни модели, ни... вообще ничего! Вон, к примеру, статическая картинка -- её вы тоже будете через бэкэнд отдавать? Что вообще для вас бэкэнд? Скрипт на PHP? Контроллер? Сервисный слой? ORM?

O>4xx может означать только некорректно сформированные на уровне HTTP данные.


А что есть уровень HTTP? Где границы этого уровня? Кто, например, по вашему должен обрабатывать Conditional GET?

O>5xx — сервер недоступен, запрос следует повторить позже.


А если сервер доступен, но ошибка в входных параметрах? К примеру, неверная сигнатура запроса или ошибочный ID сессии? Отбросим все ситуации, для которых уместно отдавать 403 и 404.

O>Давайте рассмотрим еще один (очень упрощенный) пример.

O>Допустим, есть веб-сервис покупок, через который я POST-запросом могу заказать себе, скажем,
O>ящик водки. При успешном заказе сервер возвращает 200 OK, а с моего счета списывается некая сумма.
O>В определенный момент мой баланс становится нулевым и денег на водку не хватает — на очередной
O>запрос сервер должен возвратить что ? "200 OK" или "400 Bad Request" ? Допустим, первый вариант.

Должен вернуть 400 Bad Request. Или, как вариант, 402 Payment Required. А вы предлагаете возвращать 200 OK?

O>Объясните, почему прокси вдруг должен закэшировать ответы с кодом 200, но при этом передавать

O>ответы с кодом 400 мимо кэша ?

Ответы с кодом 400 кэшируются точно так же как ответ 200. Причем я не совсем понимаю почему говоря о кэшировании, вы всё время упоминаете прокси? Кэширование чего-либо на стороне прокси -- это частный случай. Кэширование не является основной функцией прокси, это скорее сопутствующая функция, которую просто очень часто используют. Основная функция прокси -- быть посредником для клиентов при обращении к веб-серверам. При этом прокси может ничего не кэшировать. В то же время большинство браузеров имеют встроенный кэш, который ничем не отличается от того, который можно встретить у прокси. Ну разве что настроек в браузере поменьше. В RFC-2616 есть понятие HTTP Cache, который отделен от прокси.

Так вот, коды 200 и 400 кэшируются ровно так и ровно столько, сколько указано в заголовке Cache-Control. Если в этом заголовке не указано и нет запрета, то кэши (имеется в виду как кэш браузера, так и кэши одного или нескольких прокси-серверов, стоящих в цепочке) могут кэшировать ответ, если это не запрещено протоколом. Если не хотите, чтобы кэш угадывал сколько можно кэшировать ваш ответ, не играйте с ним в угадайку, говорите ему точно сколько -- передавайте заголовок Cache-Control.

Про запрет кэширования 4xx ответов сказано только в отношении неизвестных статусов, которые неизвестны клиенту. Ибо мало ли чё там в расширении протокола HTTP...

O>Код из группы 500, понятное дело. Запрос не был обработан бэк эндом, для клиента

O>это достаточная для принятия нужного решения информация.

Я не понимаю, если ошибка произошла на стороне бэкэнда, то кто сообщает клиенту 500-ую ошибку? Фронтэнд?
-- С уважением, Павел Мелехов, Екатеринбург.
Re[10]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: anonymous Россия http://denis.ibaev.name/
Дата: 19.10.12 10:37
Оценка:
Здравствуйте, Geri, Вы писали:

G>Параметры в HTTP являются частью запроса и они должны быть так же согласованы и непротиворечивы, как заголовки запроса (как слова в предложениях). Они могут быть верными "орфографически", но не согласованы между собой.


Нет. Параметры — это либо часть URI, либо часть тела запроса, и собственно к HTTP отношения не имеют никакого. Протокол просто не в курсе, что там в теле сообщения или в части запроса URI, это не его уровень. За обработку этих данных отвечает не он. А вот когда он не понимает, где тело, а где заголовки, и что вообще такое ему прислали, вот это синтаксическая ошибка.
Re[12]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.10.12 10:45
Оценка:
Здравствуйте, okman, Вы писали:
Упс, мой длинный ответ на предыдущий вариант поста пропал

O>2xx — запрос обработан бэк эндом. Клиент переходит к формированию и отправке следующего.

O>4xx может означать только некорректно сформированные на уровне HTTP данные.
O>5xx — сервер недоступен, запрос следует повторить позже.
O>Все ясно, как день.
Не, неясно. Вы только что писали, что неправильно сформированный запрос возвращает 200 Ok. С точки зрения сервера, он ничуть не лучше ошибки в урле или глаголе — запрос выполнить так и не удалось. Тем не менее клиент уверен, что можно ехать дальше. Вижу противоречие.

O>Да, все верно. На уровне HTTP мы используем сжатие, кэширование, даже контроль целостности.

O>А уровень данных играет по своим правилам. Я лишь предлагаю не смешивать их воедино, а
O>аккуратно изолировать друг от друга. При этом разница насколько тонкая, что остается
O>почти незаметной. Фактически, все различия сводятся только к тому, чтобы не использовать на
O>уровне данных (HTML/JSON/XML/другое) механизмы из нижележащего уровня (HTTP/TCP/UDP/другое),
O>такие как коды состояний или опции сжатия, а оставить их на совести того самого уровня, который ниже.
O>Впечатление, будто я призываю отказываться от встроенных механизмов HTTP — в корне неверное.
Вы почему-то ставите "уровень данных" выше "уровня HTTP". Реальный прикладной протокол описывает всё сразу — и набор глаголов, и набор существительных. Нельзя сказать, что что-то одно "выше уровнем", чем что-то другое.
Вон Geri по соседству спрашивает — кто должен обрабатывать Conditional GET? Кто должен обрабатывать Partial Get?
Кто должен анализировать Accept- хидеры?

O>Это вовсе не так. Прокомментировал выше.

Однако с кодами статусов вы дела иметь почему-то не хотите. Странно.


O>Давайте рассмотрим еще один (очень упрощенный) пример.

O>Допустим, есть веб-сервис покупок, через который я POST-запросом могу заказать себе, скажем,
O>ящик водки. При успешном заказе сервер возвращает 200 OK, а с моего счета списывается некая сумма.
O>В определенный момент мой баланс становится нулевым и денег на водку не хватает — на очередной
O>запрос сервер должен возвратить что ? "200 OK" или "400 Bad Request" ? Допустим, первый вариант.
O>Объясните, почему прокси вдруг должен закэшировать ответы с кодом 200, но при этом передавать
O>ответы с кодом 400 мимо кэша ? Требование идемпотентности к запросам POST не предъявляется.
O>А по поводу кода 400 в RFC 2616 сказано: "The client SHOULD NOT repeat the request without
O>modifications" — клиенту не рекомендуется повторять тот же самый запрос, не включив в него
O>модификации. Как раз в этом случае прокси с большей вероятностью закэширует ответ-400 на
O>один и тот же запрос и будет все время его возвращать.
Нет. По поводу кода надо читать раздел 13.4. По поводу POST — раздел 9.5. При прочих равных вероятность кэширования 200 выше, т.к. она требует от прокси нарушать только один пункт RFC, а кэширование 400 — сразу два.
Сам выбранный вами протокол для покупки является антипримером. Вы выбрали самый неудачный из глаголов HTTP для реализации потенциально опасной операции. Вот получите вы таймаут на клиенте — как вам понять, списались деньги или ещё нет? Освойте идемпотентность — это единственное решение проблемы двух генералов.


O>У нас разное понимание семантики кода 200.

O>Я считаю, что код 200 — это "запрос обработан". Или, точнее говоря, "сообщение доставлено".
O>Что это за запрос и что это за сообщение — уже не забота HTTP.
Очень странная позиция. Вопросу о том, "что это за сообщение", посвящён целый раздел №9.
HTTP не сводится к "доставке сообщений". Он ещё и подразумевает некоторую семантику. И если её не удалось обеспечить, то сервер обязан вернуть соотвествующий статус.

O>Ошибка транспорта — это когда в GET-запросе не указывается URL или Host.

O>Логическая ошибка — это когда я пытаюсь заказать водку, а денег на счету нет.
Отлично. И чем эта ошибка хуже той, когда я пытаюсь заказать водку, а водки нет?
А эта — чем когда я пытаюсь скачать фотку водки, а фотки нет?
Почему-то в этих случаях принято возвращать 404, а не 200 Фото не найдено.

O>Код из группы 500, понятное дело. Запрос не был обработан бэк эндом, для клиента

O>это достаточная для принятия нужного решения информация.
Что вы называете "бэк-ендом"? Сообщение было "доставлено" ажно до обработчика в ASP.Net — куда дальше-то.
И бэк-енд там что-то наобрабатывал. Вплоть до момента вылета. C точки зрения фронтенда всё хорошо.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Geri Россия http://web-notes.ru/
Дата: 19.10.12 11:10
Оценка:
Здравствуйте, anonymous, Вы писали:

A>Здравствуйте, Geri, Вы писали:


G>>Параметры в HTTP являются частью запроса и они должны быть так же согласованы и непротиворечивы, как заголовки запроса (как слова в предложениях). Они могут быть верными "орфографически", но не согласованы между собой.


A>Нет. Параметры — это либо часть URI, либо часть тела запроса, и собственно к HTTP отношения не имеют никакого.


Ну, вот в этом мы с Вами в корне не сходимся. Я считаю GET/POST-параметры частью HTTP-запроса, вы считаете их чем-то отдельным от него. Скажите, а заголовки HTTP являются частью запроса или они тоже, как и параметры, отдельно от HTTP? В чем разница с точки зрения HTTP между параметрами и заголовками? Из чего следует, что одно является частью HTTP, а другое нет? Желательно со ссылкой на RFC2616.

A>Протокол просто не в курсе, что там в теле сообщения или в части запроса URI, это не его уровень. За обработку этих данных отвечает не он.


Это его уровень. HTTP -- это прикладной протокол. Доказательство этого в том, что мы из своего приложения должны устанавливаем код ответа, различные заголовки и т.п. А не только данные возвращаем.

A> А вот когда он не понимает, где тело, а где заголовки, и что вообще такое ему прислали, вот это синтаксическая ошибка.


А если HTTP понимает где тело, а где заголовки, но какого-то очень нужного заголовка в запросе не хватает? К примеру, нет заголовка Host, а клиент при этом HTTP 1.1. Это синтаксическая ошибка или логическая?
-- С уважением, Павел Мелехов, Екатеринбург.
Re[12]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: anonymous Россия http://denis.ibaev.name/
Дата: 19.10.12 11:31
Оценка:
Здравствуйте, Geri, Вы писали:

G>>>Параметры в HTTP являются частью запроса и они должны быть так же согласованы и непротиворечивы, как заголовки запроса (как слова в предложениях). Они могут быть верными "орфографически", но не согласованы между собой.

A>>Нет. Параметры — это либо часть URI, либо часть тела запроса, и собственно к HTTP отношения не имеют никакого.
G>Ну, вот в этом мы с Вами в корне не сходимся. Я считаю GET/POST-параметры частью HTTP-запроса, вы считаете их чем-то отдельным от него. Скажите, а заголовки HTTP являются частью запроса или они тоже, как и параметры, отдельно от HTTP? В чем разница с точки зрения HTTP между параметрами и заголовками? Из чего следует, что одно является частью HTTP, а другое нет? Желательно со ссылкой на RFC2616.

Давайте лучше Вы покажете, где в RFC 2616 хоть что-то сказано про GET- и POST-параметры. Описание URI там заканчивается на query, не раскрывая его содержимого. О содержимом тела запроса тоже ничего не сказано.

A>>Протокол просто не в курсе, что там в теле сообщения или в части запроса URI, это не его уровень. За обработку этих данных отвечает не он.

G>Это его уровень. HTTP -- это прикладной протокол. Доказательство этого в том, что мы из своего приложения должны устанавливаем код ответа, различные заголовки и т.п. А не только данные возвращаем.

С таким же успехом можно заявить, что слово «hypertext» в его названии обязывает протокол разбираться в HTML. Да, он прикладной, но уровень всё же не тот. Он доставляет данные, но ему не важна внутренняя структура данных.

A>> А вот когда он не понимает, где тело, а где заголовки, и что вообще такое ему прислали, вот это синтаксическая ошибка.

G>А если HTTP понимает где тело, а где заголовки, но какого-то очень нужного заголовка в запросе не хватает? К примеру, нет заголовка Host, а клиент при этом HTTP 1.1. Это синтаксическая ошибка или логическая?

Синтаксис запроса HTTP 1.1 обязывает указывать заголовок Host. В RFC сказано:

Servers MUST report a 400 (Bad Request) error if an HTTP/1.1 request does not include a Host request-header.

Re[13]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Geri Россия http://web-notes.ru/
Дата: 19.10.12 12:27
Оценка:
Здравствуйте, anonymous, Вы писали:

G>>Ну, вот в этом мы с Вами в корне не сходимся. Я считаю GET/POST-параметры частью HTTP-запроса, вы считаете их чем-то отдельным от него. Скажите, а заголовки HTTP являются частью запроса или они тоже, как и параметры, отдельно от HTTP? В чем разница с точки зрения HTTP между параметрами и заголовками? Из чего следует, что одно является частью HTTP, а другое нет? Желательно со ссылкой на RFC2616.

A>Давайте лучше Вы покажете, где в RFC 2616 хоть что-то сказано про GET- и POST-параметры. Описание URI там заканчивается на query, не раскрывая его содержимого. О содержимом тела запроса тоже ничего не сказано.

Не очень красиво передергивать. В подтверждение своих слов я могу привести BNF-схему запроса из которой однозначно следует, что URI со всеми query-параметрами и телом запроса, содержащим, например, POST-параметры, входит в понятие HTTP-запроса:

        Request       = Request-Line              ; Section 5.1
                        *(( general-header        ; Section 4.5
                         | request-header         ; Section 5.3
                         | entity-header ) CRLF)  ; Section 7.1
                        CRLF
                        [ message-body ]          ; Section 4.3


G>>Это его уровень. HTTP -- это прикладной протокол. Доказательство этого в том, что мы из своего приложения должны устанавливаем код ответа, различные заголовки и т.п. А не только данные возвращаем.

A>С таким же успехом можно заявить, что слово «hypertext» в его названии обязывает протокол разбираться в HTML. Да, он прикладной, но уровень всё же не тот. Он доставляет данные, но ему не важна внутренняя структура данных.

Кому "ему"? HTTP живет сам по себе? Отдельно от приложения? Нет! Приложение реализует некий функционал в соответствии с правилами, описанными в HTTP. Функционал у сервера может быть самый разнообразный, общий только набор статусов, заголовков и т.п.

Кстати, я так и не понял, вы согласны с тем, что HTTP -- это прикладной протокол или нет?

G>>А если HTTP понимает где тело, а где заголовки, но какого-то очень нужного заголовка в запросе не хватает? К примеру, нет заголовка Host, а клиент при этом HTTP 1.1. Это синтаксическая ошибка или логическая?

A>Синтаксис запроса HTTP 1.1 обязывает указывать заголовок Host. В RFC сказано:
A>

Servers MUST report a 400 (Bad Request) error if an HTTP/1.1 request does not include a Host request-header.


Хорошо. Молодцы, что не попались. Но почему вы считаете, что синтаксис HTTP ограничен только тем, что написано в RFC2616? HTTP намеренно сделан расширяемым, чтобы удовлетворять всем потребностям, которые невозможно учесть в основной части протокола. Протокол открыто разрешает создание новых кодов статусов, новых методов запроса, новых заголовков запроса и ответа. Неужели эти расширения не могут накладывать свои ограничения на синтаксис запросов? Неужели мы не можем создать заголовок, аналогичный заголовку Host, отсутствии которого мы бы считали нарушением синтаксиса нашего расширения HTTP и должны были бы возвращать 400 Bad Request? Если можем, то почему мы не можем устанавливать какие-то свои правила синтаксиса в соответствии с требованиями конкретных запросов? Почему я не могу объявить, например, что запрос "/api/getuserinfo" имеет синтаксис, предусматривающий передачу параметра "id" (в порядке расширения HTTP-протокола) и на этом основании возвращать 400 Bad Request если этого параметра нет? Я считаю, что основным критерием для легитимности возврата сервером статуса 400 Bad Request является:

10.4.1 400 Bad Request

The request could not be understood by the server


Если сервер (в лице веб-приложения, запущенного под ним) не может понять запрос из-за того, что нет нужного параметра, то из этого автоматически следует нарушение синтаксиса запроса, т.е. его достаточности, полноты, непротиворечивости.
-- С уважением, Павел Мелехов, Екатеринбург.
Re[13]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: okman Беларусь https://searchinform.ru/
Дата: 19.10.12 13:29
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, okman, Вы писали:

S>Упс, мой длинный ответ на предыдущий вариант поста пропал

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

S>Вы только что писали, что неправильно сформированный запрос возвращает 200 Ok.


Нигде я такого не писал.

S>Вы почему-то ставите "уровень данных" выше "уровня HTTP". Реальный прикладной протокол описывает всё сразу — и набор глаголов, и набор существительных. Нельзя сказать, что что-то одно "выше уровнем", чем что-то другое.


HTTP выше TCP. Так пойдет ?

S>Вон Geri по соседству спрашивает — кто должен обрабатывать Conditional GET? Кто должен обрабатывать Partial Get?

S>Кто должен анализировать Accept- хидеры?

Тот, кто и всегда.

S>Однако с кодами статусов вы дела иметь почему-то не хотите. Странно.


Я против перегрузки кодов состояний HTTP значениями логических ошибок веб-сервиса.
Например, когда "400 Bad Request" может означать какой-нибудь некорректный URL в строке запроса,
что на счету клиента недостаточно средств и что "мы по субботам не работаем".
Во-первых, чтобы отличить эти ошибки одна от другой, клиенту придется лезть в тело ответа,
возиться с gzip-ом и кодировками, а потом разбираться, что имел в виду сервер.
Во-вторых, представьте систему, где сервер может возвращает два и более статуса.
Например, статус успеха плюс предупреждение. Как это все будет накладываться на HTTP ?
Будем изобретать вторую статусную строку или новые заголовки ?

S>По поводу кода надо читать раздел 13.4. По поводу POST — раздел 9.5. При прочих равных вероятность кэширования 200 выше, т.к. она требует от прокси нарушать только один пункт RFC, а кэширование 400 — сразу два.

S>Сам выбранный вами протокол для покупки является антипримером. Вы выбрали самый неудачный из глаголов HTTP для реализации потенциально опасной операции. Вот получите вы таймаут на клиенте — как вам понять, списались деньги или ещё нет? Освойте идемпотентность — это единственное решение проблемы двух генералов.

А при чем тут идемпотентность вообще ?
У меня может рухнуть сеть между отправкой сервером ответа и приемом его на клиенте.
К рассматриваемому вопросу это вообще не относится. Проблема будет в любом случае, верну я код 200 или 400.

S>Очень странная позиция.


Потому что она не совпадает с Вашей ?

S>Вопросу о том, "что это за сообщение", посвящён целый раздел №9.

S>HTTP не сводится к "доставке сообщений". Он ещё и подразумевает некоторую семантику. И если её не удалось обеспечить, то сервер обязан вернуть соотвествующий статус.

Мы ходим кругами вокруг одного и того же.
Семантика POST-запроса, в моем понимании, заключается в загрузке данных на сервер.
Плюс,

responses to this method are not cacheable, unless the response includes
appropriate Cache-Control or Expires header fields.

Сообщение доставлено ? Да.
Сервер обработал операцию ? Да. Все, работа POST на этом закончена, возвращаем 2xx.
То, что у Вас другая точка зрения, я в курсе, повторяться не стоит.

O>>Ошибка транспорта — это когда в GET-запросе не указывается URL или Host.

O>>Логическая ошибка — это когда я пытаюсь заказать водку, а денег на счету нет.

S>Отлично. И чем эта ошибка хуже той, когда я пытаюсь заказать водку, а водки нет?

S>А эта — чем когда я пытаюсь скачать фотку водки, а фотки нет?
S>Почему-то в этих случаях принято возвращать 404, а не 200 Фото не найдено.

Вы предлагаете совмещать в одном статусе 404 все три ответа — "фото не найдено",
"нет водки на складе" и "запрашиваемый URL не найден", причем с разных логических уровней ?
Это основное, против чего я выступаю.

S>Что вы называете "бэк-ендом"? Сообщение было "доставлено" ажно до обработчика в ASP.Net — куда дальше-то.

S>И бэк-енд там что-то наобрабатывал. Вплоть до момента вылета. C точки зрения фронтенда всё хорошо.

Нет, не все. Потому что запрос не был обработан и фронт энд не может сформировать для клиента
полноценный ответ. Поэтому ему придется отдать код 500.

Дальнейшее обсуждение представляется мне бессмысленным.
Re[14]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Geri Россия http://web-notes.ru/
Дата: 19.10.12 14:59
Оценка:
Здравствуйте, okman, Вы писали:

А вы можете всё-таки ответить что вы понимаете под бэкэндом и фронтэндом?

И кто всё-таки обрабатывает Conditional GET?

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

Например, мы сделали веб-сервис, который управляет роботом, способным брать бутылки водки из хранилища и отправлять их нам пневмопочтой. Если сегодня пятница и мы хотим напиться, мы выполняем запрос к такому веб-серверу по протоколу HTTP. Запрос мог бы выглядеть, скажем, так:

PUSH /погреб/секция_B/стеллаж_2/ячейка_239 HTTP/1.1
Host: pneumo-vodka.local
Transport: pneumo-post


На наш запрос робот идёт в подвал, ищет там нужную ячейку. Всё это время веб-сервер держит соединение и мы видем в строке статуса браузера "Waiting response...". Наконец, робот находит ячейку, но обнаруживает её пустой, он говорит об этом серверу и сервер отправляет нам ответ вида:

HTTP/1.1 404 Not Found
Expires: Mon, 22 Oct 2012 05:00:00 GMT


Из чего мы понимаем, что мы ошиблись с местом -- по указанному URI бутылки водки нет. Повторять этот запрос снова, пожалуй, смысла нет, т.к. вряд ли на этом месте бутылка быстро появится. В заголовке Expires указано время утро понедельника, когда будет очередной завоз бутылок и когда самое раннее в этом месте бутылка может появиться. До этого момента данный ответ могут спокойно кэшировать браузеры и прокси. Если мы запросим снова до момента, указанного в Expires, то ответ может быть взят из кэша, сервер его даже не увидит, но для нас это нормально. Если же после, то кэш не будет использоваться, запрос будет обработан сервером, а там либо снова 404, либо 200 OK (бутылка отправлена).
-- С уважением, Павел Мелехов, Екатеринбург.
Re[14]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: anonymous Россия http://denis.ibaev.name/
Дата: 19.10.12 17:03
Оценка: :)
Здравствуйте, Geri, Вы писали:

A>>Давайте лучше Вы покажете, где в RFC 2616 хоть что-то сказано про GET- и POST-параметры. Описание URI там заканчивается на query, не раскрывая его содержимого. О содержимом тела запроса тоже ничего не сказано.

G>Не очень красиво передергивать. В подтверждение своих слов я могу привести BNF-схему запроса из которой однозначно следует, что URI со всеми query-параметрами и телом запроса, содержащим, например, POST-параметры, входит в понятие HTTP-запроса:

Я ничего не передёргиваю. Да, они входят в запрос, я этого не отрицаю, но об их внутренней структуре ничего не сказано: в теле может быть что угодно, в query — аналогично. И задача HTTP — доставить это «что угодно», не вникая в содержание.

G>>>Это его уровень. HTTP -- это прикладной протокол. Доказательство этого в том, что мы из своего приложения должны устанавливаем код ответа, различные заголовки и т.п. А не только данные возвращаем.

A>>С таким же успехом можно заявить, что слово «hypertext» в его названии обязывает протокол разбираться в HTML. Да, он прикладной, но уровень всё же не тот. Он доставляет данные, но ему не важна внутренняя структура данных.
G>Кому "ему"? HTTP живет сам по себе? Отдельно от приложения? Нет! Приложение реализует некий функционал в соответствии с правилами, описанными в HTTP. Функционал у сервера может быть самый разнообразный, общий только набор статусов, заголовков и т.п.

Ну и что, протокол-то тут при чём?

G>Кстати, я так и не понял, вы согласны с тем, что HTTP -- это прикладной протокол или нет?


Согласен.

G>Хорошо. Молодцы, что не попались. Но почему вы считаете, что синтаксис HTTP ограничен только тем, что написано в RFC2616? HTTP намеренно сделан расширяемым, чтобы удовлетворять всем потребностям, которые невозможно учесть в основной части протокола.


Вы пытаетесь увести разговор в сторону, мы ж говорим о HTTP, а не о его расширениях. В расширениях может быть что угодно, но тогда так и нужно говорить: я использую расширение HTTP, где 400-я ошибка несёт дополнительный смысл.
Re[14]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.10.12 10:23
Оценка:
Здравствуйте, okman, Вы писали:

S>>Вы только что писали, что неправильно сформированный запрос возвращает 200 Ok.

O>Нигде я такого не писал.
Странно. Топик называется "можеи ли веб-приложение возвращать 400 Bad Request при некорректных параметрах". Я так понял, что вы отстаиваете его право возвращать в таких случаях 200.

O>HTTP выше TCP. Так пойдет ?

Так — пойдёт. Но это не является темой дискуссии.

S>>Кто должен анализировать Accept- хидеры?

O>Тот, кто и всегда.
Это не ответ. Обычно, в типичном современном веб-приложении, их вообще никто не обрабатывает. Вы предлагаете поощрять эту порочную практику?

O>Я против перегрузки кодов состояний HTTP значениями логических ошибок веб-сервиса.

O>Например, когда "400 Bad Request" может означать какой-нибудь некорректный URL в строке запроса,
O>что на счету клиента недостаточно средств и что "мы по субботам не работаем".
Вы описали три разных ситуации. Под код 400 подходит только одна из них, остальные две — нет. Совершенно непонятно, почему вы хотите их чесать под одну гребёнку.

O>Во-первых, чтобы отличить эти ошибки одна от другой, клиенту придется лезть в тело ответа,

O>возиться с gzip-ом и кодировками, а потом разбираться, что имел в виду сервер.
Клиенту, вообще-то, всегда надо возиться с gzip-ом и кодировками, и разбираться, что имел в виду сервер. Такая уж у клиента работа. Если он не хотел видеть gzip, то нефиг было выставлять его в Accept-Encoding.
И как раз использование различных кодов ошибок позволяет клиенту быстрее и проще понять, в чём он накосячил.
Я не вижу совершенно никаких преимуществ в использовании кода 200 для этих же ошибок.

O>Во-вторых, представьте систему, где сервер может возвращает два и более статуса.

O>Например, статус успеха плюс предупреждение. Как это все будет накладываться на HTTP ?
Ну, если отвлечься от того, что мне такая система вовсе не нравится, то прекрасно будет накладываться.
O>Будем изобретать вторую статусную строку или новые заголовки ?
Будем действовать в духе протокола. Если запрошенное действие выполнить удалось — отдаём 2xx. Если нет — то действуем по реальным обстоятельствам. Точнее я вам ответить не могу, т.к. задача не поставлена. Что именно должен делать клиент в ответ на этот warning? Если ничего — то в пень такой warning, это шум в канале.

O>А при чем тут идемпотентность вообще ?

O>У меня может рухнуть сеть между отправкой сервером ответа и приемом его на клиенте.
O>К рассматриваемому вопросу это вообще не относится. Проблема будет в любом случае, верну я код 200 или 400.
Это правда. Это относится к тому, как вообще надо проектировать протоколы. Вы легким росчерком пера заложили в протокол грабли замедленного действия. Если вы так решаете реальные задачи, то постарайтесь сделать так, чтобы пользователи ваших протоколов не знали ваш домашний адрес.

O>Потому что она не совпадает с Вашей ?

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

O>Семантика POST-запроса, в моем понимании, заключается в загрузке данных на сервер.

Давайте, для интересу, откроем таки RFC. Раз уж вы начали его цитировать:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line

Видите? Речь не о том, чтобы "загрузить данные". Их нужно ещё и разместить как подчинённый ресурс. И вот если этого сделать не получилось, то никаких 200 возвращать не надо.

O>Плюс,

responses to this method are not cacheable, unless the response includes
O>appropriate Cache-Control or Expires header fields.

Сообщение доставлено ? Да.

O>Сервер обработал операцию ? Да. Все, работа POST на этом закончена, возвращаем 2xx.
O>То, что у Вас другая точка зрения, я в курсе, повторяться не стоит.
Моя точка зрения, в отличие от вашей, поддержана RFC.

O>Вы предлагаете совмещать в одном статусе 404 все три ответа — "фото не найдено",

O>"нет водки на складе" и "запрашиваемый URL не найден", причем с разных логических уровней ?
Нет. Только первый и третий. И уровень — один и тот же. Я вам повторно намекаю про то, что для клиента никаких "уровней" нет. Если в вашем протоколе клиент видит уровни устройства сервера, то вы плохо спроектировали протокол. Понятно, почему, или нужно пояснять?

O>Нет, не все. Потому что запрос не был обработан и фронт энд не может сформировать для клиента

O>полноценный ответ. Поэтому ему придется отдать код 500.
Ну вот видите. Осталось научить вас понимать, что значит "запрос был обработан", и мы придём к консенсусу.

O>Дальнейшее обсуждение представляется мне бессмысленным.

Ну что вы, это так увлекательно
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.