Здравствуйте, 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 при некорректных парам
Здравствуйте, 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 при некорректных парам
Здравствуйте, 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 при некорректных парам
Мне приятно, что поднятая мною тема стала предметом активного обсуждения, но в то же время мне несколько неудобно из-за того, что я сам несколько выпал из своей же темы. Я получаю по почте новые сообщения и внимательно их читаю. Я перестал сюда писать, т.к. лично для себя я давно всё решил. Моя позиция полностью совпадает с позициями 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 при некорректных пара
Здравствуйте, okman, Вы писали:
S>>А, я-то думал, что вы против возврата 500. O>Я против ситуации, когда 500 может возвращаться кем-то еще, кроме серверного фронт энда.
Я не очень понимаю что вы имеете в виду, когда говорите о фронтэнде и бэкэнде. Судя по гуглу, примерно половина программистов рунета путают понятия backend и back-office, называя бэкэндом админку сайта. Но вы вроде бы не из этих. В моём представлении бэкэндом можно считать, например, серверную часть в приложениях типа клиент-сервер (например, ajax), в традиционных веб-приложениях без ajax бэкэндом можно считать базу данных, классы моделей и все прочие классы, кроме контроллеров и шаблонов. Но представлять это можно по-разному, суть от этого не поменяется. Поэтому мне бы и хотелось понять какое значение вкладываете вы и почему это бэкэнд не может возвращать статус 500. Вот, база данных у вас это фронтэнд или бэкэнд? По мне так это стопроцентный бэкэнд. Ошибка подключения к базе данных или ошибка SQL приведет к возврату какого статуса HTTP клиенту? 5xx или 4xx? Я думаю после вашего ответа на этот вопрос многое должно проясниться.
-- С уважением, Павел Мелехов, Екатеринбург.
Re[10]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
Здравствуйте, 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 при некорректных пара
Здравствуйте, 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 при некорректных пара
Здравствуйте, 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 при некорректных пара
Здравствуйте, Geri, Вы писали:
G>Параметры в HTTP являются частью запроса и они должны быть так же согласованы и непротиворечивы, как заголовки запроса (как слова в предложениях). Они могут быть верными "орфографически", но не согласованы между собой.
Нет. Параметры — это либо часть URI, либо часть тела запроса, и собственно к HTTP отношения не имеют никакого. Протокол просто не в курсе, что там в теле сообщения или в части запроса URI, это не его уровень. За обработку этих данных отвечает не он. А вот когда он не понимает, где тело, а где заголовки, и что вообще такое ему прислали, вот это синтаксическая ошибка.
Re[12]: Может ли веб-приложение возвращать 400 Bad Request при некорректных пара
Здравствуйте, 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 при некорректных пара
Здравствуйте, 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 при некорректных пара
Здравствуйте, 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. Это синтаксическая ошибка или логическая?
Здравствуйте, anonymous, Вы писали:
G>>Ну, вот в этом мы с Вами в корне не сходимся. Я считаю GET/POST-параметры частью HTTP-запроса, вы считаете их чем-то отдельным от него. Скажите, а заголовки HTTP являются частью запроса или они тоже, как и параметры, отдельно от HTTP? В чем разница с точки зрения HTTP между параметрами и заголовками? Из чего следует, что одно является частью HTTP, а другое нет? Желательно со ссылкой на RFC2616. A>Давайте лучше Вы покажете, где в RFC 2616 хоть что-то сказано про GET- и POST-параметры. Описание URI там заканчивается на query, не раскрывая его содержимого. О содержимом тела запроса тоже ничего не сказано.
Не очень красиво передергивать. В подтверждение своих слов я могу привести BNF-схему запроса из которой однозначно следует, что URI со всеми query-параметрами и телом запроса, содержащим, например, POST-параметры, входит в понятие HTTP-запроса:
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 при некорректных пара
Здравствуйте, 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 при некорректных пара
А вы можете всё-таки ответить что вы понимаете под бэкэндом и фронтэндом?
И кто всё-таки обрабатывает Conditional GET?
Код 404 означает, что не найден некий объект, в отношении которого мы совершаем какое-то запрашиваемое действие. При этом в зависимости от типа запрашиваемого объекта не найденным может быть как фотография, так и бутылка водки. Мы сами знаем что мы запрашиваем, поэтому у нас не составляет труда понять чего именно не найдено.
Например, мы сделали веб-сервис, который управляет роботом, способным брать бутылки водки из хранилища и отправлять их нам пневмопочтой. Если сегодня пятница и мы хотим напиться, мы выполняем запрос к такому веб-серверу по протоколу HTTP. Запрос мог бы выглядеть, скажем, так:
На наш запрос робот идёт в подвал, ищет там нужную ячейку. Всё это время веб-сервер держит соединение и мы видем в строке статуса браузера "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 при некорректных пара
Здравствуйте, 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 при некорректных пара
Здравствуйте, 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>Дальнейшее обсуждение представляется мне бессмысленным.
Ну что вы, это так увлекательно
Уйдемте отсюда, Румата! У вас слишком богатые погреба.