Метод HTTP QUERY для команд фронтенда: безопасное чтение с телом запроса
Узнайте, когда метод HTTP QUERY превосходит GET и POST для сложных фильтров, как использовать его с fetch, а также какие требования предъявляются к CORS, кэшированию и поддержке инфраструктуры.
У экранов поиска и фильтрации существует постоянная проблема с API. Если кодировать каждый фильтр в строке запроса GET, URL становится длинным и неудобным для использования; если отправлять фильтры в формате JSON через метод POST, это означает использование метода, предназначенного для обозначения изменения состояния, тогда как на самом деле речь идет о чтении данных. Метод HTTP QUERY разработан именно для устранения этой проблемы. В этой статье объясняется, что означает метод QUERY, как отправлять его из приложения React с помощью fetch, и какие компоненты вашей инфраструктуры, от CORS до кэшей, требуют внимания перед тем, как полагаться на него.
Проблема, которую решает QUERY
Список продуктов с несколькими фильтрами быстро приводит к формированию запроса вроде этого:
/products?category=laptop&brand=Apple&minPrice=50000&maxPrice=150000&rating=4
Этот подход работает, но каждый новый фильтр увеличивает длину строки, вложенные или повторяющиеся значения (несколько брендов, диапазон цен, порядок сортировки, пагинация) требуют специальных правил кодирования, а чрезмерно длинные URL могут столкнуться с ограничениями по длине на серверах, прокси и в логах.
Обычным решением является использование метода POST с телом в формате JSON. Это удобнее для реализации на стороне клиента, но усложняет формирование контракта между клиентом и сервером. Метод POST не является ни безопасным, ни идемпотентным, поэтому посредники не могут быть уверены, что повторная отправка запроса не приведет к проблемам, кэши по умолчанию не будут хранить ответы, и любой, кто работает с API, должен изучать документацию, чтобы понять, что этот конкретный запрос методом POST предназначен только для чтения данных.
Что такое QUERY
QUERY — это метод HTTP, с помощью которого клиент просит сервер выполнить запрос, описанный в содержимом запроса. По данным на момент написания текста, IETF опубликовал его в качестве стандарта в июне 2026 года под номером RFC 10008; перед цитированием проверьте его текущий статус в индексе RFC. Вместо того чтобы включать параметры прямо в URL, клиент отправляет их в теле запроса:
QUERY /products HTTP/1.1
Content-Type: application/json
{
"category": "laptop",
"brands": ["Apple", "Dell"],
"price": {
"min": 50000,
"max": 150000
}
}
Сервер обрабатывает запрос и возвращает соответствующие результаты. То, что отличает QUERY от POST, — это их семантика: QUERY считается безопасным, поскольку не изменяет целевой ресурс, и идемпотентным, что означает, что отправка его дважды даёт тот же результат, что и один раз. Именно эти свойства позволяют клиентам, прокси и кэшам рассматривать его как операцию чтения. Идемпотентность, например, означает, что клиент или посредник может автоматически повторить неудачный запрос без риска возникновения дублирующих побочных эффектов, чего делать не следует в случае с POST.
Выбор между GET, POST и QUERY
QUERY не заменяет другие методы. У каждого из них по-прежнему есть чёткая роль:
- GET остаётся стандартным методом для простого получения данных: ресурс по ID или короткий список с несколькими простыми параметрами.
Для фронтенда преимущество заключается в том, что сложные карты состояния фильтров напрямую передаются в теле запроса, а контракт API четко указывает, что ничего не изменяется.
Отправка запроса QUERY из React
Представьте компонент React, который хранит текущие фильтры продуктов в объекте:
const filters = {
category: "laptop",
brands: ["Apple", "Dell"],
price: {
min: 50000,
max: 150000
},
rating: 4
};
При использовании метода QUERY этот объект можно сериализовать и отправить в неизменном виде. Приведенный ниже помощник использует fetch с пользовательским именем метода и телом в формате JSON:
const searchProducts = async (filters) => {
const response = await fetch("/api/products", {
method: "QUERY",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(filters)
});
Вторая часть той же функции проверяет статус ответа и парсит полученный результат:
if (!response.ok) {
throw new Error("Failed to fetch products");
} return response.json();
};
Помимо имени метода, это идентично запросу типа POST. Изменение носит семантический, а не синтаксический характер: теперь запрос объявляется как запрос-запрос. Обратите внимание на два практических момента. Стандарт Fetch преобразует в верхний регистр только несколько хорошо известных имён методов, поэтому всегда пишите "QUERY" с заглавными буквами. Кроме того, в отличие от методов GET и HEAD, данные которых fetch не разрешает отправлять вместе с телом запроса, для метода QUERY такая передача допускается.
Один из компромиссов касается пользовательских интерфейсов. Фильтры, закодированные в URL, можно сохранить в закладках и передать другим пользователям, а также они сохраняются при перезагрузке страницы. Тело запроса типа QUERY этого не делает. Если важны переносимые ссылки, возможно, стоит отражать состояние фильтров в URL страницы на стороне клиента, одновременно отправляя структурированный запрос в API.
Проверьте поддержку на всем пути запроса
Стандартизация метода не означает, что каждый компонент, обрабатывающий трафик, его понимает. Запрос браузера проходит через несколько уровней перед тем, как достичь приложения, и любой из них может отклонить или исказить незнакомый метод. Перед использованием QUERY убедитесь в следующем:
- Поведении браузера и функции
fetch()в поддерживаемых браузерах. - Конфигурации CORS в API.
- API-шлюзах и обратных прокси.
- CDN-сервисах и кэшах на периферии.
- Средствах аутентификации и авторизации.
- Инструментах мониторинга, логирования и отслеживания.
- Механизмах маршрутизации и парсинга тела запросов в фреймворке бэкенда.
Некоторые уровни могут разрешать только фиксированный список методов, а некоторые могут игнорировать тело запроса для неизвестных методов. Тестируйте решение «от конца до конца» в среде, максимально приближенной к производственной, а не только на локальном сервере.
CORS всегда требует предварительной проверки
QUERY не входит в список методов, разрешенных для CORS (GET, HEAD и POST). Это означает, что запрос QUERY из браузера другого источника всегда запускает предварительную проверку: перед фактическим запросом браузер отправляет запрос OPTIONS, чтобы узнать, разрешен ли метод QUERY.
Если ваше приложение React и API находятся в разных источниках, сервер должен ответить на эту предварительную проверку заголовком Access-Control-Allow-Methods, в котором указан метод QUERY, а также все другие заголовки, используемые в вашем запросе, например Content-Type. JSON-тело также принудительно запускает предварительную проверку для метода POST, поэтому дополнительные затраты часто не являются проблемой, но метод должен быть указан явно.
Это легко упустить во время разработки. Инструменты вроде Postman и curl не обеспечивают соблюдение правил CORS, поэтому конечная точка может работать без проблем там, но отклоняться в браузере.
Кэширование возможно, но более сложно
Ответы на запросы типа QUERY можно кэшировать, что является одним из основных преимуществ этого метода по сравнению с POST. Проблема заключается в том, что ответ зависит от содержимого тела запроса, а не только от URL. Рассмотрим два таких тела запросов, отправленных на один и тот же конечный пункт:
{
"brand": "Apple"
}
{
"brand": "Dell"
}
Они должны возвращать разные результаты. Поэтому при принятии решения о возможности повторного использования сохраненного ответа кэш должен включать содержимое запроса, а также его тип медиафайла, в ключ кэша. Кроме того, кэши могут нормализовать содержимое (например, игнорировать незначительные пробелы в JSON), чтобы эквивалентные запросы хранились в одной записи.
Для разработчиков React и Next.js важно понимать, что при кэшировании QUERY не следует рассматривать его как «GET с телом запроса». HTTP-кэши браузеров, CDN и кэши функций загрузки на уровне фреймворков пока могут не использовать тело запроса в качестве ключа, поэтому необходимо уточнять поведение каждого слоя, а не предполагать успешное нахождение в кэше.
Как QUERY связан с GraphQL
GraphQL часто упоминается в одних и тех же разговорах, но эти два подхода работают на разных уровнях. GraphQL предоставляет язык для описания необходимых данных и модель для их получения. QUERY же является лишь операцией на уровне передачи данных: он определяет, как HTTP должен обрабатывать запросы с содержимым QUERY. В настоящее время клиенты GraphQL обычно отправляют запросы с использованием метода POST; теоретически сервер GraphQL может принимать операции чтения через QUERY, но QUERY не заменяет GraphQL, и они могут сосуществовать в зависимости от архитектуры API.
Стоит ли мигрировать существующие API?
Как правило, нет, по крайней мере не только из-за существования QUERY. Если точка входа для поиска уже хорошо работает с использованием методов GET или POST, её замена приведёт к дополнительной работе по миграции и обеспечению совместимости при ограниченной пользе. QUERY наиболее целесообразен при разработке новой точки входа, запросы к которой являются:
- Только для чтения.
Это предоставляет командам принципиальную альтернативу постоянному использованию метода POST, когда запросы типа GET становятся слишком сложными для обработки.
Основные выводы
- Используйте метод GET для простого получения данных и сохраняйте простоту простых запросов.
- Рассмотрите использование метода QUERY для сложных запросов с только чтением, которые требуют структурированного тела запроса.
- Не ожидайте ускорения: метод QUERY меняет способ представления запроса, а не скорость работы бэкенда или сети.
- Перед внедрением в производство проверьте поддержку этого метода в браузерах, прокси, шлюзах, CDN и вашей фреймворковой среде.
- Настройте CORS для явного разрешения данного метода и протестируйте его в реальном браузере.
- Проверьте все ключи уровней кэширования в теле запроса перед тем, как полагаться на кэшированные ответы QUERY.
- Следите за внедрением этого решения в экосистеме: именно на страницах поиска, панелях управления и приложениях с большим объемом данных QUERY, скорее всего, принесет первые результаты.