В HTTP появился метод QUERY. Пора прощаться с POST /search?
У бэкенд-разработчиков много лет был довольно неловкий выбор.
Пока фильтров мало, используем GET:
GET /orders?page=2&status=PAID&sort=createdAt,desc
Потом поиск усложняется. Появляются диапазоны дат, группы условий, вложенные фильтры. Query string постепенно превращается в плохо читаемый DSL. Заодно приходится учитывать ограничения на длину URI и то, что адрес запроса может попасть в логи.
Обычно в этот момент появляется такой эндпойнт:
POST /orders/search Content-Type: application/json
{ “status”: [“PAID”, “SHIPPED”], “createdAt”: { “from”: “2026-06-01”, “to”: “2026-06-30” }, “customer”: { “country”: “NL” } }
Решение рабочее. POST вообще не ограничен созданием ресурсов. Сервер может обрабатывать его тело по собственной семантике.
Проблема в другом: на уровне HTTP POST считается потенциально небезопасным и не идмептентным. Прокси, клиенты и другая инфраструктура не знают, что наш /search только читает данные. Такой запрос нельзя автоматически повторять или полноценно кэшировать без дополнительных договоренностей.
Передать тело в GET технически возможно. Но RFC 9110 говорит, что у содержимого GET-запроса нет общепринятой семантики. Некоторые серверы и промежуточные узлы могут отклонить такой запрос. Среди причин упоминаются даже атаки класса request smuggling.
В июне 2026 года IETF опубликовала RFC 10008 с новым методом QUERY:
QUERY /orders HTTP/1.1 Content-Type: application/json Accept: application/json
{ “status”: [“PAID”, “SHIPPED”], “total”: { “min”: 100, “max”: 1000 } }
QUERY предназначен для запросов, описание которых передается в теле. Формат может быть любым, если он обозначен через Content-Type: JSON, SQL, JSONPath или собственный язык фильтрации.
Спецификация закрепляет за QUERY три свойства:
- safe - клиент не запрашивает изменение состояния целевого ресурса - idempotent - запрос можно безопасно повторить - cacheable - ответ разрешено кэшировать
Для кэша есть отдельное правило: ключ должен учитывать тело запроса и связанные с ним метаданные. Поэтому существующие CDN и reverse proxy не начнут кэшировать QUERY сами по себе. Им потребуется поддержка нового метода.
QUERY также умеет работать с conditional requests. А сервер может сообщить о допустимых форматах через новый заголовок Accept-Query.
Что со Spring?
В актуальном Spring Framework полноценной поддержки QUERY пока нет. Проблема находится именно на уровне фреймворка: в RequestMethod отсутствует такое значение, поэтому обычный @RequestMapping нельзя привязать к QUERY.
Обойти ограничение можно через functional endpoints, собственный HandlerMapping или ручную проверку метода. Для нового стандарта это слишком много самодельной инфраструктуры.
Сейчас открыт PR с поддержкой RFC 10008. Команда Spring рассчитывает подготовить ее к Spring Framework 7.1, который ожидается в ноябре 2026 года. Точная версия пока не гарантирована.
Так что переписывать все POST /search сегодня рано. Ждем нормальной поддержки в Spring, клиентах и прокси. Потом уже можно будет с чистой совестью бежать менять поисковые POST-запросы на QUERY.
RFC 10008: https://www.rfc-editor.org/info/rfc10008/
Spring Framework PR: https://github.com/spring-projects/spring-framework/pull/34993