В июне 2026 года опубликован RFC 10008 — The HTTP QUERY Method. Он добавил в HTTP новый стандартизованный метод QUERY, который также появился в реестре HTTP‑методов IANA: запрос с телом к конкретному адресу, который по смыслу остаётся чтением и не должен менять данные на сервере.

Метод нужен для знакомого случая: нужно передать сложные параметры поиска, фильтрации или отчёта, а по семантике это всё ещё безопасная операция чтения.
Например:
вывести все мои заказы с 1 июля 2025 года по сегодня, только оплаченные, но ещё не полученные;
дать из системы статистики срез посещений только для посетителей из Казахстана, только в дневное время и только для браузеров на macOS;
найти в журнале безопасности все успешные входы администраторов за последние 30 дней, но исключить входы из офисных сетей и сервисных учётных записей.
Обычный GET для таких запросов часто неудобен: параметры быстро превращаются в длинный URI или в собственный мини‑язык фильтрации внутри строки запроса. POST удобнее для передачи структуры, но передаёт не тот сигнал промежуточной инфраструктуре.
Напомню: HTTP как протокол появился раньше своих RFC: в RFC 1945 сказано, что HTTP используется в Вебе с 1990 года. Сам RFC 1945 вышел в мае 1996 года и описал HTTP/1.0 — фактически зафиксировал распространённую к тому моменту практику. После этого HTTP много раз уточнялся: HTTP/1.1, разделение семантики и транспорта, HTTP/2, HTTP/3. Появление нового метода в 2026 году — ещё одно уточнение в протоколе, который всё ещё развивается.
Исходная проблема
Когда нужно просто получить страницу, объект или список по понятному адресу, пусть даже с несколькими уточняющими параметрами, GET подходит хорошо:
GET /orders?status=paid&limit=100 HTTP/1.1 Host: api.example.com
Такой запрос легко воспроизвести, положить в закладку, записать в журнал и сохранить в кэше. Браузеры, прокси, CDN, серверные фреймворки и средства диагностики десятилетиями хорошо понимают эту модель.
Но в API часто встречается другой сценарий: поиск по вложенным условиям, выбор набора полей, сортировка, диапазоны дат, группировки, ограничения по правам доступа. Например:
{ "where": { "and": [ { "field": "status", "eq": "paid" }, { "field": "created_at", "gte": "2026-01-01" }, { "field": "email", "like": "%@example.com" } ] }, "select": ["id", "email", "total", "created_at"], "sort": ["-created_at"], "limit": 100 }
Это можно закодировать в строку запроса URI, но дальше начинаются обычные неудобства:
URI становится длинным и плохо читается;
появляются ограничения на длину URI в клиентах, прокси, балансировщиках и серверах;
сложные структуры приходится кодировать в формат, который для них не очень удобен;
параметры чаще попадают в журналы доступа, историю браузера, отчёты WAF, CDN и APM;
каждая комбинация параметров выглядит как отдельный URI, даже если для приложения это один и тот же вид операции.
RFC 10008 прямо называет такие причины среди мотивов для QUERY. В частности, документ напоминает, что разные участники цепочки обработки могут иметь собственные лимиты, и заранее знать самый строгий из них обычно нельзя.
Почему не GET с телом
На первый взгляд можно было бы оставить метод GET, но передавать сложные параметры в теле:
GET /orders/search HTTP/1.1 Host: api.example.com Content-Type: application/json { "status": "paid", "limit": 100 }
Технически HTTP‑сообщение может содержать тело и при GET. Проблема в другом: семантика GET не задаёт смысл такого тела. В RFC 9110 сказано, что содержимое в GET не имеет общей определённой семантики, не может менять смысл запроса и целевой URI, а некоторые реализации могут отклонять такие запросы по соображениям совместимости или безопасности.
На практике запрос проходит не только через приложение. Между клиентом и обработчиком могут быть:
клиентская библиотека;
браузер;
CDN;
WAF;
балансировщик нагрузки;
обратный прокси;
API‑шлюз;
ingress‑контроллер;
промежуточный обработчик авторизации;
кэш;
трассировка и сбор метрик.
Если хоть один компонент посчитает GET с телом «необычным случаем», поведение становится зависимым от конкретной инфраструктуры. Где‑то тело будет проигнорировано, где‑то запрос заблокируют, где‑то фреймворк не даст прочитать тело в обычном обработчике. Внутри одной системы это ещё можно удержать под контролем, но для публичного и переносимого описания API такой вариант создаёт слишком много оговорок.
Почему не POST /search
Самый распространённый обходной путь — использовать POST:
POST /orders/search HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: application/json { "status": "paid", "limit": 100 }
Этот вариант рабочий. Его понимают фреймворки, прокси и клиенты. Многие API построены именно на таком подходе и будут так жить ещё долго.
Минус в том, что POST сам по себе не говорит инфраструктуре, что операция безопасная и идемпотентная. Скажем, разработчики конкретного сервиса знают, что POST /orders/search только ищет заказы и не меняет данные на сервере, так что такой адрес их не смущает. Однако всё, что идёт дальше по цепочке, про это локальное соглашение не знает. Обобщённый HTTP‑клиент, кэш, прокси, механизм повторов или инструмент документации видит просто POST. А POST может создать ресурс, изменить состояние, запустить задачу или выполнить любую другую обработку по правилам ресурса.
Из‑за этого приходится переносить важную часть смысла в имя адреса:
POST /orders/search
Слово search помогает человеку, но не меняет семантику HTTP‑метода. QUERY позволяет выразить это на уровне протокола:
QUERY /orders
Метод сообщает, что клиент просит ресурс выполнить запрос, описанный в теле, и вернуть результат без изменения состояния целевого ресурса.
Один и тот же поиск: раньше и с QUERY
Возьмём обычный пример: в интерфейсе заказов пользователь собирает фильтр. Нужны оплаченные заказы за период, только по нескольким странам, с выбором полей и сортировкой.
Через GET это часто превращается в длинную строку запроса:
GET /orders?status=paid&from=2026-01-01&to=2026-06-30&country=DE&country=FR&fields=id,total,currency,created_at&sort=-created_at&limit=100 HTTP/1.1 Host: api.example.com
Пока параметров мало, такой вариант нормален. Когда появляются группы условий, вложенные and/or, полнотекстовый поиск, списки идентификаторов и настройки агрегации, URI становится плохо читаемым. Каждый, кто хоть раз смотрел на адреса сайтов на ядре Битрикс, в этом месте обычно уже не хмыкает, а тяжело вздыхает. Разработчики начинают придумывать собственные соглашения: JSON в параметре filter, base64 в строке запроса, массивы через повторяющиеся ключи, мини‑язык фильтрации внутри одного параметра.
Например:
GET /orders?filter=%7B%22status%22%3A%22paid%22%2C%22limit%22%3A100%7D HTTP/1.1 Host: api.example.com
Работать это может, но диагностика становится неприятной: надо декодировать строку, следить за лимитами URI и помнить, что весь фильтр с высокой вероятностью окажется в журналах доступа.
Через POST тот же поиск выглядит удобнее для приложения:
POST /orders/search HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: application/json { "status": "paid", "period": { "from": "2026-01-01", "to": "2026-06-30" }, "countries": ["DE", "FR"], "fields": ["id", "total", "currency", "created_at"], "sort": ["-created_at"], "limit": 100 }
Так проще описывать структуру запроса, валидировать её и расширять без усложнения URI. Поэтому POST /search стал привычным решением.
Но на уровне HTTP это всё равно POST. Если где‑то включён автоматический повтор запросов, кэширование, аудит опасных операций или отдельная политика для изменяющих методов, инфраструктура не знает, что перед ней только чтение. Это знание живёт в документации, названии адреса и коде сервиса.
С QUERY тот же пример можно записать так:
QUERY /orders HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: application/json { "status": "paid", "period": { "from": "2026-01-01", "to": "2026-06-30" }, "countries": ["DE", "FR"], "fields": ["id", "total", "currency", "created_at"], "sort": ["-created_at"], "limit": 100 }
Разница не в количестве строк. Разница в том, что структура запроса остаётся в теле, а HTTP‑метод одновременно сообщает: это безопасная и идемпотентная операция чтения в области ресурса /orders.
В старой модели смысл приходилось распределять по нескольким местам:
GETговорил «чтение», но заставлял упаковывать сложный ввод в URI;POSTдавал удобное тело, но не говорил, что операция безопасная;имя
/searchобъясняло намерение человеку, но не меняло поведение HTTP‑инфраструктуры.
QUERY собирает эти признаки в одном месте: метод остаётся методом чтения, а параметры передаются как нормальное содержимое запроса.
Что именно стандартизовал QUERY
Пример запроса:
QUERY /orders HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: application/json { "status": "paid", "created_after": "2026-01-01", "fields": ["id", "email", "total", "created_at"], "sort": ["-created_at"], "limit": 100 }
В RFC 10008 у QUERY зафиксированы несколько свойств.
Во‑первых, это безопасный метод в смысле HTTP: клиент не запрашивает и не ожидает изменения состояния целевого ресурса. Это не запрещает серверу писать журналы, считать метрики или создавать временные вспомогательные ресурсы для результата. Такие побочные действия вообще возможны и у GET.
Во‑вторых, метод идемпотентный: повтор того же запроса должен иметь тот же ожидаемый эффект, что и один запрос. Это важно для автоматических повторов после сетевого сбоя.
В‑третьих, содержимое запроса является нормальной частью семантики метода. Формат тела задаётся Content-Type, а желаемый формат ответа — обычным заголовком Accept.
Если упростить:
GET— безопасное чтение, параметры обычно находятся в URI;POST— обработка тела запроса по правилам ресурса, возможно с изменением состояния;QUERY— безопасное и идемпотентное чтение, где параметры находятся в теле запроса.
Формат тела и Accept‑Query
Так как смысл QUERY находится в теле запроса, сервер должен понимать его формат. RFC 10008 требует отклонять запрос, если Content-Type отсутствует или не соответствует содержимому.
Например, ресурс может принимать JSON:
QUERY /contacts HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: application/json { "select": ["surname", "given_name", "email"], "limit": 10, "match": { "email": "*@example.com" } }
Или application/x-www-form-urlencoded:
QUERY /contacts HTTP/1.1 Host: api.example.com Content-Type: application/x-www-form-urlencoded Accept: application/json select=surname,given_name,email&limit=10&match=email%3D*%40example.com
Или специализированный формат, например JSONPath:
QUERY /errata.json HTTP/1.1 Host: api.example.com Content-Type: application/jsonpath Accept: application/json $..[?@.status=="Rejected" && @.submit_date>"2024"]["doc-id"]
Для объявления поддерживаемых форматов появился заголовок ответа Accept-Query:
HTTP/1.1 200 OK Accept-Query: application/json, "application/jsonpath"
С его помощью ресурс может сообщить клиенту: QUERY здесь поддерживается, а тело запроса может быть в таких‑то типах данных. Это полезно для клиентов, документации и диагностики. Важно, что Accept-Query не заменяет Accept: первый описывает формат запроса, второй — формат ответа.
Location и Content‑Location
У QUERY есть интересная деталь: сервер может назначить URI результату запроса или самому запросу.
Допустим, клиент отправляет:
QUERY /contacts HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: application/json { "select": ["surname", "given_name", "email"], "limit": 10, "match": "email=*@example.*" }
Сервер может ответить так:
HTTP/1.1 200 OK Content-Type: application/json Content-Location: /contacts/stored-results/17 Location: /contacts/stored-queries/42 [ { "surname": "Smith", "given_name": "John", "email": "smith@example.org" } ]
Content-Location здесь указывает на ресурс, соответствующий возвращённому представлению. Например, на сохранённый результат:
GET /contacts/stored-results/17 HTTP/1.1 Host: api.example.com Accept: application/json
Location может указывать на ресурс, который представляет сам запрос. Клиент сможет повторить его через обычный GET, не отправляя тело заново:
GET /contacts/stored-queries/42 HTTP/1.1 Host: api.example.com Accept: application/json
Для отчётов, аналитических интерфейсов и сложных фильтров это практичная модель. Пользователь собрал фильтр, сервер сохранил его как отдельный ресурс, ссылку можно передать коллеге или использовать повторно. При этом нужно заранее решить, что именно сохраняется: снимок результата на момент выполнения или формула запроса, которая при следующем обращении даст актуальные данные.
Кэширование
RFC 10008 описывает ответы на QUERY как кэшируемые. Но из этого не следует, что существующие CDN, обратные прокси и браузеры сразу начнут эффективно кэшировать такие запросы.
Для GET ключ кэша обычно строится вокруг URI и заголовков, влияющих на представление. Для QUERY одного URI недостаточно:
QUERY /orders HTTP/1.1 Content-Type: application/json {"status":"paid"}
QUERY /orders HTTP/1.1 Content-Type: application/json {"status":"cancelled"}
URI одинаковый, тело разное, результат тоже должен быть разным. Поэтому ключ кэша обязан учитывать содержимое запроса и связанные метаданные: Content-Type, кодирование содержимого и другие параметры, которые влияют на обработку.
Отдельная тема — нормализация. Эти два JSON‑документа могут иметь одинаковый смысл для приложения:
{"status":"paid","limit":10}
{ "limit": 10, "status": "paid" }
По байтам они разные. По смыслу конкретного API — возможно, одинаковые. RFC допускает нормализацию для построения ключа кэша, но это требует знания формата и правил конкретного ресурса. Ошибка в нормализации может привести к выдаче чужого или неверного ответа.
Если результат запроса зависит от того, кто именно его отправил, какие у этого пользователя права доступа и какие данные ему вообще разрешено видеть, кэширование QUERY надо проектировать так же аккуратно, как кэширование GET с авторизацией. Новый метод не отменяет Cache-Control, Vary и обычную проверку прав доступа.
Практичный вариант для некоторых систем: первый запрос выполнить через QUERY, получить Location для эквивалентного ресурса, а последующие обращения делать через GET. Это упрощает жизнь кэшу и клиентам, если такая модель подходит приложению.
Логирование и чувствительные данные
Перенос параметров из URI в тело запроса снижает вероятность, что они случайно окажутся в журналах доступа. Но тело запроса не становится защищённым местом.
Содержимое QUERY может попасть в:
журналы приложения;
отладочные журналы;
APM;
распределённую трассировку;
WAF;
API‑шлюз;
отчёты об исключениях;
тестовые дампы.
Поэтому в QUERY не стоит передавать секреты, токены, приватные ключи и другие данные, которые не должны проходить через инфраструктурные журналы.
Если сервер создаёт URI для сохранённого запроса или результата, этот URI тоже не должен раскрывать чувствительные параметры.
Плохой вариант:
Location: /stored-queries/email=ivan@example.com&passport=1234567890
Лучше использовать непрозрачный идентификатор:
Location: /stored-queries/42f4b0c9
Доступ к такому ресурсу должен проверяться так же строго, как доступ к исходным данным.
CORS и браузеры
Для браузерных приложений есть отдельный момент: QUERY не входит в CORS‑safelisted methods. Поэтому межсайтовый запрос из браузера потребует предварительный OPTIONS.
Браузер сначала отправит:
OPTIONS /orders HTTP/1.1 Origin: https://frontend.example.com Access-Control-Request-Method: QUERY Access-Control-Request-Headers: content-type
Сервер должен явно разрешить метод:
HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://frontend.example.com Access-Control-Allow-Methods: GET, POST, QUERY, OPTIONS Access-Control-Allow-Headers: content-type
Для межсерверных API это обычно несущественно. Для SPA и публичных браузерных API это надо проверять до выката, иначе новая семантика упрётся в настройки CORS.
Лимиты размера остаются
QUERY не означает, что теперь можно отправлять запросы любого размера. Он убирает необходимость помещать сложные параметры в URI, но тело запроса всё равно ограничивается настройками клиента, прокси, WAF, API‑шлюза, сервера приложений, фреймворка и самого приложения.
У больших запросов остаются обычные эксплуатационные вопросы:
таймауты;
ограничение частоты запросов;
стоимость выполнения;
нагрузка на базу данных или поисковый движок;
лимиты памяти;
сложность диагностики;
стоимость кэширования.
Корректная формулировка такая: QUERY переносит данные запроса из URI в тело HTTP‑сообщения, где с ними обычно удобнее работать и где проще задавать контролируемые лимиты.
Где QUERY подходит
QUERY стоит рассматривать для операций, которые одновременно:
читают данные и не должны менять состояние целевого ресурса;
требуют сложного или объёмного ввода;
выигрывают от явной HTTP‑семантики безопасного и идемпотентного метода;
плохо укладываются в обычную строку запроса URI.
Типичные примеры:
сложный поиск;
аналитические отчёты;
фильтрация по вложенным условиям;
запросы к документным коллекциям;
JSONPath‑ или XPath‑подобные запросы;
GraphQL‑подобные выборки, если конкретная инфраструктура поддерживает такой способ;
API, где сейчас есть
POST /search, хотя операция фактически только читает данные.
Пример отчёта:
QUERY /reports/revenue HTTP/1.1 Host: api.example.com Content-Type: application/json Accept: text/csv { "group_by": ["month", "country"], "metrics": ["gross_revenue", "refunds", "net_revenue"], "period": { "from": "2026-01-01", "to": "2026-06-30" } }
Здесь GET с параметрами быстро превратился бы в длинный плохо читаемый URI, а POST скрыл бы от инфраструктуры тот факт, что операция не должна менять состояние ресурса.
Где QUERY не нужен
Для простых случаев лучше оставить привычные методы.
Получение ресурса по идентификатору:
GET /users/123 HTTP/1.1 Host: api.example.com
Список с несколькими параметрами:
GET /orders?status=paid&limit=50 HTTP/1.1 Host: api.example.com
Создание ресурса:
POST /orders HTTP/1.1 Host: api.example.com Content-Type: application/json { "user_id": 123, "items": [] }
Частичное изменение:
PATCH /orders/123 HTTP/1.1 Host: api.example.com Content-Type: application/json { "status": "cancelled" }
Удаление:
DELETE /orders/123 HTTP/1.1 Host: api.example.com
Если операция меняет состояние, запускает задачу, создаёт экспорт, отправляет письмо или оставляет бизнес‑эффект, QUERY для неё не подходит. В таких случаях лучше честно использовать POST, PATCH, PUT или другой метод с подходящей семантикой.
Что должно измениться вокруг QUERY
Отправить QUERY через curl несложно. Daniel Stenberg, автор curl, отдельно разбирал это в заметке QUERY with curl:
curl -X QUERY \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ --data '{"status":"paid","limit":100}' \ https://api.example.com/orders
Но новый HTTP‑метод становится практически полезным не в момент публикации RFC. Его должны начать нормально пропускать, понимать и диагностировать все участники цепочки. В этом смысле QUERY сейчас находится в обычной для нового стандарта ситуации: спецификация уже есть, а массовая поддержка в инструментах будет появляться постепенно.
Первый слой — клиенты.
Низкоуровневые HTTP‑клиенты часто умеют отправлять произвольный метод: строка метода для них просто часть HTTP‑запроса. Но поверх них обычно есть более удобные обёртки: SDK, REST‑клиенты, клиентский код, сгенерированный по OpenAPI‑описанию, механизмы повторов, политики идемпотентности, типизированные перечисления методов. В таких местах QUERY может не пройти проверку, не попасть в список разрешённых методов или не получить правильное поведение для повторов.
С браузерами тоже есть нюанс. Есть стандарт Fetch — это спецификация, по которой браузеры реализуют fetch(), сетевые запросы из JavaScript, CORS и связанные с этим правила. В нём запрещёнными методами считаются CONNECT, TRACE и TRACK; произвольный метод вроде QUERY сам по себе в этот список не попадает. Но QUERY не входит в список простых CORS‑методов (GET, HEAD, POST), поэтому межсайтовый запрос через fetch потребует предварительный OPTIONS. Обычная HTML‑форма метод QUERY не отправит, навигация по ссылке тоже. Кэш браузера, DevTools, Service Worker и клиентские библиотеки надо проверять отдельно, а не считать поддержку полной только потому, что один fetch в одном браузере отправил запрос.
На июль 2026 года публично объявленных сроков поддержки QUERY в Chrome, Firefox и Safari нет. Обсуждение интеграции в Fetch уже началось, но до стадии «это обычный браузерный метод, который везде работает предсказуемо» ещё нужно пройти путь через спецификации, реализации и совместимость с промежуточной инфраструктурой.
Второй слой — серверное приложение.
Маршрутизатор фреймворка должен разрешить новый метод, документация должна уметь его описать, тестовый клиент должен уметь его вызвать, промежуточный обработчик авторизации должен применять к нему правильные правила. Если в коде где‑то есть проверка вида «разрешены только GET, POST, PUT, PATCH, DELETE», QUERY остановится внутри приложения.
Третий слой — промежуточная инфраструктура.
Здесь список длиннее:
CDN и обратные прокси должны пропускать метод и корректно работать с телом запроса;
кэши должны строить ключ с учётом тела и
Content-Type, иначе кэширование будет небезопасным;WAF должен понимать, что тело у
QUERYожидаемо, и применять к нему правила проверки;API‑шлюз должен разрешить метод в маршрутах и политиках безопасности;
балансировщик и ingress‑контроллер не должны отбрасывать запрос как неизвестный;
корпоративный прокси, например Squid, может иметь правила доступа по HTTP‑методу;
журналы и трассировка должны показывать метод, тело, статус и причину отказа достаточно подробно для диагностики.
С Squid и похожими прокси важно не гадать по названию продукта, а смотреть конкретную конфигурацию. В Squid есть ACL по методу и правила http_access; в одних установках неизвестный метод может пройти, в других корпоративная политика разрешит только привычный набор. С WAF ситуация похожая: часть правил завязана на список методов, часть — на ожидание тела только у POST, PUT и PATCH, часть — на сигнатуры конкретных API.
Четвёртый слой — эксплуатационные соглашения.
Нужно решить, как QUERY участвует в:
повторных попытках после сетевых ошибок;
ограничении частоты запросов;
учёте стоимости тяжёлых поисковых операций;
журналировании тела запроса;
маскировании чувствительных данных;
мониторинге ошибок
400,405,415,422;схемах OpenAPI и автогенерации клиентов;
интеграционных тестах через реальные прокси и шлюзы.
Во многих системах есть явный список разрешённых HTTP‑методов. Если где‑то перечислены только GET, POST, PUT, PATCH, DELETE и OPTIONS, новый метод может получить 405 Method Not Allowed или быть заблокирован ещё до приложения.
Поэтому разумный путь внедрения выглядит так:
Выбрать операции, которые действительно являются безопасными и идемпотентными.
Описать формат тела запроса: JSON Schema, JSONPath,
application/x-www-form-urlencodedили собственный тип данных.Добавить
QUERYрядом с существующимPOST /search, если такой адрес уже есть.Явно публиковать поддержку метода и формата:
Allow: GET, QUERY, OPTIONS, HEAD Accept-Query: application/json
Проверить всю инфраструктуру: шлюзы, WAF, прокси, CORS, журналы, мониторинг и тесты.
Отдельно спроектировать кэширование,
Location,Content-Locationи сохранённые запросы, если они нужны.
На первом этапе POST /orders/search и QUERY /orders могут использовать одну серверную логику. Разница будет в HTTP‑семантике и в том, как эту операцию видят клиенты и промежуточные компоненты.
Итог
Теперь у нас есть QUERY — стандартизованный HTTP‑метод для безопасных и идемпотентных запросов с телом.
Он полезен там, где GET со строкой запроса становится громоздким, GET с телом плохо поддерживается инфраструктурой, а POST /search не выражает смысл операции на уровне HTTP.
Существующие API не нужно срочно переписывать. Но для новых поисковых, аналитических и документных API QUERY даёт более точную модель:
QUERY /resource Content-Type: application/json { "...": "сложный запрос на чтение" }
Старые способы остаются нормальными там, где они просты и понятны. Новый метод нужен для случаев, где параметры запроса уже стали полноценным структурированным вводом, а операция всё ещё должна оставаться чтением.
тот же плакатик из КДПВ

Комментарии (24)

SWATOPLUS
03.07.2026 21:43Люди занимаются какой-то ерундой. Гораздо лучше было бы добавить в GET и DELETE поддержку body, сначала в стандарт, а потом потихоньку в браузеры, серверы, фреймворки и так далее. В статье говориться, что вроде как будет проще что бы все поддерживали новый метод, но мне кажется, что повсеместная поддержка нового метода будет не раньше поддержки IPv6.
Что лучше в этом случае делать? Забить на HTTP-методы с их семантикой и всегда использовать POST в API и GET для статического контента.

RifleR
03.07.2026 21:43Гораздо лучше было бы добавить в GET и DELETE поддержку body
не лучше. Если б добавили официально body в GET, получилось бы две спецификации: старая GETv1 и новая GETv2. И как тогда узнать, какую версию поддерживает определенный клиент/сервер/фреймворк? Да, посмотреть в документации, но где гарантия, что автор не забудет там указать точную версию или не посчитает данное уточнение несущественным? А вот с отдельным названием все становится проще. Написано, что есть поддержка QUERY - значит 100% есть. Не написано - 100% нет.

skymal4ik
03.07.2026 21:43Не знаю, чего за негатив в комментах, но мне нравится пропозал, использовал бы его там, где надо отправить сложный фильтр и получить по нему данные.
Пост, патч и пут семантически подразумевают изменение или создание данных. А создавать длиннющий урл для гета выглядит не очень эстетично.
А так закинул json с фильтрами в тело, заслал query и получил результат (который сервер или прокси ещё и закэшить может). Красота!

Mayurifag
03.07.2026 21:43Киллер-фича GET, а именно, что можно этот ужасно некрасивый URL (если конечно не хешировать параметры в строчку аля base64 как в статье предложено) положить в закладку или пошарить с коллегой / дать для дебаггинга разработчику, уходит.
Может если только браузер будет предлагать эту шушлайку скопировать, но опять же стандарт такой строчки надо бы чтобы всеми браузерами поддерживался + строчка должна все равно быть короче + это все равно будет раздолье для фишингов и других видов взломов, вряд ли сразу красиво придумают.
В общем, интересно, но непрактично из-за упомянутого неудобства.

slavcopost
03.07.2026 21:43Новый метод не предпологает замену GET, если URL с фильтрами и они помещаются, можно продолжать использовать GET и шарить URL. Новый метод просто дополнителная возможность для тех у кого другие требования
В спецификации нового метода предусмотрено, и в статье это указано, как делать если надо возможность сохраниять поиск для переиспользования или шарить между коллегами.

ionicman
03.07.2026 21:43А всего-то нужно было утвердить тело для GET ну и DELETE заодно, которое, внезапно, из RFC и не было никогда запрещено.
Ещё один пример, того, что люди, которые все это придумывают и сидят в различных коммитетах далеки как от программирования, так и от элементарного здравого смысла.
А потом нам с вами с этим мучиться.
P. S. очень смешно читать, что вот дескать POST меняет данные, а GET нет - это всего лишь соглашение, которое ещё и нарушается довольно часто в сложных проектах, а сделать можно как угодно.

Format-X22
03.07.2026 21:43Можно всё сделать на POST с JSON RPC, я в таком проекте участвовал. Или даже без RPC, а просто POST и там по имени в урле что-то делать. Можно сделать чтобы GET менял состояние, иногда это даже оправданно для одноразовых ссылок. Всегда можно изобрести свой стандарт поверх чего угодно и положить болт на все соглашения. И заработать свое законное место в котле в аду, потому что другие люди пытаясь интегрировать самописный велосипед и ловя отсутствие идемпотентности маловероятно что будут вас благодарить.
Стандарт нужен чтобы на него могли ориентироваться и другие люди, ни разу не видевшие проект. Промежуточные системы, прокси, фильтры безопасности и мониторинг. Для блога на пхп оно может и не надо, для любителей педального транспорта в коде - тоже. А вот для остальных стандарт, тем более такого уровня, это важный инструмент для работы.

ionicman
03.07.2026 21:43Стандарт должен быть максимально логичным, лаконичным и удобным, а иначе котёл в аду будет разработчикам данного стандарта.
Здесь абсолютно бесполезный новый метод, суть которого отлично реализуема без его введения.
Стандарт всегда лучше хаоса, но не тогда, когда сам стандарт это хаос.
HemulGM
Не было бы проще и логичнее, просто разрешить серверу и клиенту, принимать и передавать, соответственно, тело в GET, вместо того чтобы вынуждать добавлять обработку целого "нового" метода?
Тем более, что многие серверы и клиенты уже и так позволяют это делать.
Void-Cowboy
то же самое что и можно просто post сделать "безопасным" убрав проверки options и получив тот же qwery
классика из создания проблем, что бы их преодолевать. Ведь этот "стандарт" именно ради затягивания в браузеры по умолчанию и называют "стандартом". Так то можно какой угодно "запрос" собирать и отправлять.
помню была задача сделать нормальный обмен от клиента в условиях плохой сети, то есть без всех этих приседаний с кропсами и options - в итоге данные паковались в get-параметры и "разрешенные" заголовки (подпись в заголовке потому "знать ссылку" недостаточно) и это даже работало! Потому что странные фронт-енд правила - есть разные лимиты на url с параметрами, но к заголовкам лимиты тоже неслабые, даже к "безопасным"
HemulGM
По семантике GET и QUERY ничем не отличаются, в отличие от POST, который подразумевает внесение изменений.
Void-Cowboy
подразумевает кем?
"внесение изменений" некоторые гении и на GET-параметрах делают до сих пор
я еще понимаю момент что GET-параметры попадают в url потому ссылкой можно и нужно поделится, но это QWERY это просто старый добрый POST который переизобретают в облегченном виде что бы не сломать старые наверченые костыли на котрых уже много что работает
И опять таки, все это проблема из жизни фронт-ендов так как в найтиве если уж сильно хочется чего-то странного то создаешь свой заголовок и работаешь с ним, если важно выделить на уровне запросов.
Даже на хабре мелькают время от времени статьи на тему UPDATE или POST, потому проблема уж точно не в людях или удобствах, а в том что бы пропихивать 100500 параметров на сервер и получать ответ быстрее, чем сейчас позволяют браузеры со всеми танцами.
И что то мне кажется что основной потребитель тут будет в лице нейронок, так как с клиентом реактивность давно уже решают через вебсокеты, а вот нейронкам в браузере нужно или слать запрос на свой сервер что бы он запросил "правильно" или упиратся в кропсы и прочие политики междоменного взаимодейсвия.
al-chemist
Вы можете настроить инфраструктуру так, что при разрыве связи внутри — прокси, который торчит наружу — повторит запрос к внутреннему сервису несколько раз, если тот по таймауту отвалился, например. А клиент ничего и не заметит.
Сделать это можно только для идемпотентных запросов, очевидно, каковым
POSTне является. (Не нужно со мной спорить, я согласен, что это глагол ради глагола, я просто на ваш вопрос ответил.)achekalin Автор
Отличаются именно в части тела запроса.
У GET тело не имеет общей стандартной семантики, у QUERY имеет. Ради этого метод и появился.
HemulGM
По RFC у GET точно так же описано тело, как и для POST. И новый метод, опять лишь создаёт новую условность: "метод прям вот специально когда нужно тело, но нужно как GET". В то время, как тело и параметры и прочее одинаково для всех методов, без ограничений.
achekalin Автор
Идея была не в том, чтобы «разрешить отправить ещё один вид запроса», а в том, чтобы одинаково описать его смысл для всей цепочки обработки.
Проблема как раз в том, что
GETс телом уже сейчас где-то работает, а где-то нет. RFC 9110 не задаёт для телаGETобщей семантики, поэтому каждый участник цепочки передачи может трактовать его по-своему: клиент, прокси, кэш, WAF, фреймворк.QUERYпоявился не потому, что (на практике) строго нельзя было передавать тело и раньше, а потому, что для такого сценария не было отдельной стандартной семантики на уровне HTTP.POST /searchтоже остаётся рабочим вариантом, но он не сообщает инфраструктуре, что операция безопасная и идемпотентная.QUERYкак раз про это: сложный запрос в теле, но с семантикой чтения.Сделать «безопасный
POST» по локальному соглашению можно. Собственно, так многие API и живут. Но это знание остаётся локальным соглашением между клиентом и сервером. Для HTTP-инфраструктуры это всё равноPOST.HemulGM
Семантика GET никогда не запрещала передавать тело, вы же сами об этом сказали. И QUERY ничего нового (включая семантику) не дает, кроме как больших затрат на модификацию существующих библиотек.
achekalin Автор
Да, это не запрещалось (в смысле, в тело положить что угодно) - но и не было описано как возможное. Вопрос не в запрете, а в том, что это долго оставалось частным соглашением без общей протокольной семантики. А раз нет семантики, нет указания, что тело точно есть - то долетит ли это тело через WAF, и даст ли конкретная библиотека к нему доступ - это, как говорится, частные случаи.
А RFC как раз предлагает вместо частных решений решение общее, стандартное.
Vasjen
Не проще, у эндпоинта может быть много получателей, не факт что каждый из них будет корректно использовать новый стандарт старого метода, плюс нужно проследить всю цепочку - прокси, балансировщики, что везде тело передастся и нигде не дропнется.
А еще есть корпоративные системы типа AD FS и WAP, которые при множественных редиректах гарантировано вам поломают проброс тела в GET запросе.
HemulGM
Так ведь с новым стандартом нужно будет также проследить, что вся цепочка серверов умеет работать с новым методом "QUERY".
Если ответным аргументом будет: "Обновится зависимость и достаточно пересобрать".
То и с обработкой тела в GET - то же самое.
Я просто считаю, что убрать отсечение тела, если оно имеется (а оно имеется не у всех), проще, чем добавлять новый метод, который точно отсутствует у всех поголовно. И его добавление обернется куда более обширным вмешательством в код.
Format-X22
Через 10 лет квери в большинство мест завезут. А вот самодельный гет с телом или пост с пометкой - у каждого свой костыль и каждый делает по-своему, удачи в интеграциях. Костыли решили починить и сделать один вариант для всех. Для того и есть стандарты. Так то до HTTP первой версии тоже были самодельные решения. А теперь живем и считаем это обыденным.
HemulGM
Это то и не было стандартом. Это просто условность, которая не подкреплена документально в протоколе (RFC) никак.
Обработка тела GET - это не костыль. Это штатное поведение.
Xexa
Так старый стандарт не запрещал и соответственно нет необходимости вводить "новый стандарт старого метода".
Просто кто-то когда-то придумал "бестпрактикс" и понеслось, что сами себе выдумали ограничения, которых нет в протоколе изначально и в него заложен такой функционал