LINUX.ORG.RU

Стандартизирован HTTP-метод QUERY, комбинирующий возможности GET и POST

 , , ,


1

5

Инженерный комитет IETF (Internet Engineering Task Force), занимающийся развитием протоколов и архитектуры сети Интернет, придал HTTP-методу QUERY статус «Предложенного стандарта» и опубликовал связанную с ним спецификацию RFC 10008. Метод QUERY по способу отправки данных на сервер повторяет метод POST, но отличается от него ориентацией не на запись данных и изменение состояния, а на формирование запросов на чтение.

По решаемым задачам новый метод близок к GET и позволят отправлять запросы, которые могут быть повторены или перезапущены без изменения состояния на сервере. Как и в методе POST параметры запроса в QUERY передаются не в URI, а в теле запроса. Подобный подход даёт возможность передавать большой объём параметров в запросе, превышающий лимит на размер параметров в методе GET (8000 байт).

GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
Host: example.org

QUERY /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded

q=foo&limit=10&sort=-published

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

Среди областей применения метода QUERY упоминается отправка запросов к Web API, выдающих результат в формате JSON или XML, или бэкендам, генерирующим контент. Для определения возможности использования нового метода при обращении к серверу предлагается использовать метод OPTIONS, а для определения поддерживаемых форматов метод HEAD:

> OPTIONS /contacts HTTP/1.1
> Host: example.org

HTTP/1.1 200 OK
Allow: GET, QUERY, OPTIONS, HEAD

В методе QUERY предусмотрена поддержка кэширования — прокси-серверы или обработчики могут сохранить результат выполнения запроса, присвоить ему URI для последующего обращения через метод GET и вернуть информацию о выдаче прокэшированной версии через заголовок Last-Modified. Для проверки наличия изменений с прошлого запроса может применяться заголовок If-Modified-Since. Для указания альтернативных вариантов выполнения запроса в ответе могут указываться заголовки Content-Location и Location, отличия которых в том, что первый передаёт ссылку для получения результата ранее выполненного запроса, а второй предназначен для повторения запроса с теми же параметрами:

> QUERY /contacts HTTP/1.1
> Host: example.org
> Content-Type: application/x-www-form-urlencoded
> Accept: application/json
> select=surname,givenname,email&limit=10&match=%22email=*@example.*%22

HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: /contacts/stored-results/17
Location: /contacts/stored-queries/42
Last-Modified: Sat, 25 Aug 2012 23:34:45 GMT
Date: Sun, 17 Nov 2024, 16:10:24 GMT

> GET /contacts/stored-results/17 HTTP/1.1
> Host: example.org
> Accept: application/json

Помимо типа application/x-www-form-urlencoded для передачи параметров в запросах QUERY также могут напрямую использоваться расширенные форматы, такие как JSONPath (application/jsonpath), XSLT (application/xslt+xml) и SQL (application/sql). Поддерживаемые форматы возвращаются сервером в заголовке Accept-Query.

> HEAD /contacts HTTP/1.1
> Host: example.org

HTTP/1.1 200 OK
Content-Type: application/xhtml
Accept-Query: application/x-www-form-urlencoded, application/jsonpath, application/sql

> QUERY /errata.json HTTP/1.1
> Host: example.org
> Content-Type: application/jsonpath
> Accept: application/json
>
> $..[
>     ?@.errata_status_code=="Rejected"
>     && @.submit_date>"2024"
>   ]
>   ["doc-id"]

>>> Источник: OpenNET

★★★★★

Проверено: maxcom ()

Не нужно, по куче причин.

1) Всякие рассказы про «спрятать секретные данные от прокси-серверов» несостоятельны: реально их спрятать можно только если канал зашифрован (что в современном мире обычно и происходит т.е. беспокоиться об этом не стоит). Если же речь идёт про http(не s) или про https-mitm прокси, то он залогирует всё что захочет, в том числе и содержимое тела запроса. Тут разве что можно упомянуть совершенно редкий случай: соединение не зашифровано от прокси сервера, и прокси серверу ты в целом доверяешь, но на всякий случай не хочешь оставлять что-то в его логах (вдруг туда попадёт троян, уже позже, и прочитает их).

2) Сценарий, где данные шлются get-запросом и они при этом сильно секретные, весьма редок. В большинстве случаев это какие-нить идентификаторы сессий, но они давным давно переехали в куки, и таким образом для них выдуманная проблема решена ещё 20 лет назад.

3) То, что аргументы таких запросов не будут показываться в штатных логах веб-сервера - серьёзное неудобство, и, если авторы бекэнда решат таки использовать эту штуку, то скорее всего итогом будет появление костылей в конфиге веб-серверов, направленных на добавление содержимого этих query в всё тот же лог.

4) Куча софта знает что такое get/post, часто не знает ни про какие другие методы (в т.ч. даже head) и при этом прекрасно работает. Переделывать его для этого query обычно никто не соберётся.

Всякие json-xml которые внизу упоминяются дополнительно создают повод сомневаться в разумности данного документа.

firkax ★★★★★
()
Ответ на: комментарий от firkax

И ещё не успел дописать.

3а) На стороне браузера аналогичные проблемы, когда у юзера не будет нормального способа обратиться в «idempotent» странице. Но тут появление костылей менее вероятно, и соответственно более вероятно добавление мучений.

firkax ★★★★★
()
Ответ на: комментарий от ya-betmen

Нет, не аналог. По идее авторов, эти query можно слать повторно без опасений что-то повредить и без доп. переспрашиваний «а хотите ли заново отправить форму».

firkax ★★★★★
()
Ответ на: комментарий от ya-betmen

Это аналог пост, полный, зачем иметь 2 одинаковых метода не ясно.

Разве POST это поддерживает?

для передачи параметров в запросах QUERY также могут напрямую использоваться расширенные форматы, такие как JSONPath (application/jsonpath), XSLT (application/xslt+xml) и SQL (application/sql). Поддерживаемые форматы возвращаются сервером в заголовке Accept-Query.

dataman ★★★★★
() автор топика
Ответ на: комментарий от dataman

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

Хотя, конкретно заголовка Accept-Query у него наверно нет, но это мелочи, какой-то аналог либо есть либо можно свой придумать не меняя название метода.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

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

Кстати, а почему не будут? Потому что авторы документа сказали, что не надо отображать, авторы программ возьмут под козырек и не станут отображать, а иначе им скажут, что они нехорошие мальчики? :))

praseodim ★★★★★
()
Ответ на: комментарий от praseodim

Я критиковал как раз видение авторов документа. На практике этим query просто никто не будет пользоваться и проблем соответственно не будет.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Хорошая идея. Например в API у Elasticsearch / OpenSearch как раз ощущается нехватка такого метода.

maxcom ★★★★★
()

Подобный подход даёт возможность передавать большой объём параметров в запросе, превышающий лимит на размер параметров в методе GET (8000 байт).

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

maxcom ★★★★★
()

Видится неплохой идеей, которая позволит делать нечто среднее между REST и GraphQL. Можно иметь один эндпоинт, и в зависимости от типа запроса обрабатывать его. QUERY для выборки, POST для создания и так далее. Скорее нужно, чем нет. Вполне возможно поверх этого получится новый более понятный протокол вбирающий в себя REST и GraphQL.

ilinsky ★★★★★
()
Последнее исправление: ilinsky (всего исправлений: 1)
Ответ на: комментарий от maxcom

URL по смыслу это идентификатор (локатор) ресурса, а не механизм для обмена данными. Он отвечает на вопросы «куда» и «кому» адресовано сообщение. Использовать тело сообщения для передачи самого запроса это довольно логично. История с GET больше отражает проблемы юзабилити браузеров, где адресная строка не даёт возможности ввести тело сообщения.

Lucky ★★
()
Ответ на: комментарий от WatchCat

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

Lucky ★★
()

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

vazgen05 ★★★
()

Бред какой-то.

Имеющийся массовый софт делает всё то же самое послыая в POST что угодно. Формат query в POST никак не стандартизирован, разве что какое-нибудь похапе пытается автоматом парсить query в POST как name=value&…, да и то без экстремизьма, просто на всякий случай.

А немассовый софт волен использовать вообще абсолютно любые методы в HTTP запросах, которые только в голову могут придти, лишь бы не пересекались по названию с теми, которые обрабатывает сам сервер или его модули, типа CONNECT.

Stanson ★★★★★
()

А не проще ли было просто узаконить передачу параметров в теле запроса для GET?

Nervous ★★★★★
()
Ответ на: комментарий от WatchCat

А чем POST не устраивает?

Тем, что он не кешируется и retry делать нельзя. Из-за этого приходится на клиенте логику наворачивать.

maxcom ★★★★★
()
Ответ на: комментарий от Nervous

А не проще ли было просто узаконить передачу параметров в теле запроса для GET?

Это и сейчас можно, стандарт не запрещает.

maxcom ★★★★★
()

Да, что-то больно хорошо у нас GET и POST запросы работали! Можно даже сказать, годами отточенная технология. Непорядок! Надо сделать радикальный улучшайзинг и замещение новым-лучшим, чтоб жись мёдом не казалась!

Smacker ★★★★★
()
Ответ на: комментарий от dataman

Не уверен, что ради это стоило городить отдельный тип. Могли в спеку поста засунуть.

ya-betmen ★★★★★
()

Пропозал, говорите…

hobbit ★★★★★
()
Ответ на: комментарий от Lucky

POST по смыслу делает что-то необратимое

Вообще не обязательно.

Одна из функций:

Providing a block of data, such as the result of submitting a form, to a data-handling process;

Т.е. ты отправляешь блок данных, а тебе возвращается результат.

The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI

Его и сделали потому что для конкретного создания есть PUT. А роль POST она обтекаемая.

WatchCat ★★★★★
()
Последнее исправление: WatchCat (всего исправлений: 1)
Ответ на: комментарий от maxcom

Стандарт вроде не запрещает кэшировать результат пост-запроса. Требует только чтобы он имел соответствующую информацию в заголовке.

WatchCat ★★★★★
()
Ответ на: комментарий от WatchCat

Запрещает. Браузер не может отдать тебе результат предыдущего пост-запроса из кэша и не делать второго. Прокси-серверы (в обе стороны) тоже не могут так поступать.

r--r--r--
()
Последнее исправление: r--r--r-- (всего исправлений: 1)
Ответ на: комментарий от Nervous

А не проще ли было просто узаконить передачу параметров в теле запроса для GET?

Вопрос правильный. Проблема, скорее всего, не техническая.

r--r--r--
()
Ответ на: комментарий от WatchCat

Т.е. ты отправляешь блок данных, а тебе возвращается результат.

Отправленный блок данных нельзя вернуть назад. Поэтому это тоже необратимо. Спасибо за дополнение.

Lucky ★★
()
Ответ на: комментарий от ya-betmen

Если нажать f5 на странице которая сделана через post - браузер будет спрашивать подтверждение. А если с такой страницы куда-то перейти и потом нажать назад, то в зависимости от каких-то рандомных обстоятельств браузер может написать что её больше нельзя показывать. А так-то, если оба конца коммуникации тебе подконтрольны, разумеется можно делать что угодно.

firkax ★★★★★
()
Ответ на: комментарий от r--r--r--

Браузер не может отдать тебе результат предыдущего пост-запроса из кэша и не делать второго.

Opera12 могла.

Могу наврать, конечно, но почти уверен, что именно за это её и любил. И до сих пор держу под рукой на всякий случай (для ftp, в том числе).

Toxo2 ★★★★★
()
Ответ на: комментарий от Stanson

разве что какое-нибудь похапе пытается автоматом парсить query в POST как name=value&…, да и то без экстремизьма, просто на всякий случай.

Парсит в зависимости от Content-Type, причём поддерживает два разных формата (упомянутый name=value и почтовый, файлы можно только через второй слать). В целом дописывание туда поддержки json xml и прочей ерунды думаю не составляет труда, но никому не нужно (т.к. одни не выпендриваются и используют стандартный формат, а другие любят дублировать логику на скриптах даже если она есть нативная, и парсят всё самодельными костылями).

firkax ★★★★★
()
Ответ на: комментарий от Toxo2

Opera12 могла.
Могу наврать, конечно,

Так ты и врёшь. Presto кэшировал состояние документа + ресурсы и агреcсивно кэшировал все GET’ы.

И до сих пор держу под рукой

Ну, так возьми и проверь.

r--r--r--
()
Последнее исправление: r--r--r-- (всего исправлений: 1)

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

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

А так закинул json с фильтрами в тело, заслал query и получил результат (который сервер или прокси ещё и закэшить может). Красота!

skyman ★★★★★
()
Ответ на: комментарий от r--r--r--

Запрещает. Браузер не может отдать тебе результат предыдущего пост-запроса из кэша и не делать второго. Прокси-серверы (в обе стороны) тоже не могут так поступать.

Глянул стандарт, да, там разрешается кэшировать результат POST только для последующего GET и HEAD, для POST уже нельзя.

WatchCat ★★★★★
()
Ответ на: комментарий от WatchCat

Что значит «кешировать post для последующего get»? На get-запрос будет отдан результат post-а? Это какая-то чушь и так никто вменяемый не делает.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax
Responses to POST requests are only cacheable when they include explicit freshness information (see Section 4.2.1 of [CACHING]) and a Content-Location header field that has the same value as the POST's target URI (Section 8.7). A cached POST response can be reused to satisfy a later GET or HEAD request. In contrast, a POST request cannot be satisfied by a cached POST response because POST is potentially unsafe; see Section 4 of [CACHING].

Так сказано в RFC

WatchCat ★★★★★
()
Ответ на: комментарий от WatchCat

А, это какие-то специальные заголовки видимо. Хотя у меня всё равно подозрение что никто так не делает.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Типичное поведение сервера на POST запрос возвращать не 200 статус и ответ в теле, а 303 или 302 и Location: url в заголовке, который указывает браузеру куда сходить с помощью GET за результатом. В итоге браузер делает два запроса подряд: POST потом GET. Поскольку рефреш повторяет только последний запрос, то при такой реализации пользователь может спокойно обновлять страницу.

Lucky ★★
()
Последнее исправление: Lucky (всего исправлений: 1)
Ответ на: комментарий от maxcom

Это нужно в первую очередь для GraphQL, которым последние лет 10 пытаются заменить REST и компанию.

r--r--r--
()
Ответ на: комментарий от monk

QUERY поверх POST-GET выглядит как если бы grep могл записывать результаты поиска только в новый файл, который сам бы и создавал где-то в недрах /tmp, возвращая лишь его путь. Тут сразу возникают вопросы: как долго этот файл у себя хранить, кто его должен удалять, можно-ли обновлять если данные обновились и как сказать об этом клиенту, и т.п.

Lucky ★★
()
Последнее исправление: Lucky (всего исправлений: 2)

Всю жизнь для этого POST использовали, а теперь вдруг это нехорошо стало?

annulen ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.