- BrainTools - https://www.braintools.ru -
В сентябре 2026 года мы выпустили NGINX 1.31.5 с несколькими ключевыми фичами, объединёнными одной целью. Мы расширили базовые методы маршрутизации и самые важные директивы nginx, чтобы обеспечить прямую, не требующую скриптов маршрутизацию любого API‑трафика. В этом посте мы разберём самую важную возможность, которую мы назвали «предикатные локейшены» (predicate locations), и объясним, как она сочетается с остальными улучшениями, которые мы делаем для поддержки современных приложений.
В идеальном мире HTTP — отличный протокол. При правильном использовании он обеспечивает крайне быструю и надёжную коммуникацию, которая одновременно читаема человеком и программируема для клиентов и серверов.
HTTP‑взаимодействие начинается со строки запроса вроде такой:
POST /api/v1/coffee HTTP/1.1
Метод (в примере — POST) предназначен для того, чтобы сообщить бэкенд‑серверу, какое действие нужно выполнить.
URL (/api/v1/coffee) предназначен для указания на ресурс.
Заголовки, следующие за строкой запроса, предназначены для того, чтобы инструктировать сервер по различным деталям операций. Тело запроса содержит полезную нагрузку.
Маршрутизация HTTP‑запросов обычно строится вокруг URL, а в некоторых случаях — вокруг методов.
Разработчики приложений игнорируют соглашения протокола и размещают модификаторы трафика внутри заголовков и тела запроса.
В результате веб‑серверы, прокси, устройства безопасности и балансировщики нагрузки с трудом справляются с эффективной маршрутизацией трафика. Они не рассчитаны на то, что данные приложения окажутся не в тех местах.
NGINX, как и любой другой промежуточный прокси, проектировался вокруг URL.
В NGINX 1.31.5 мы сняли это ограничение и позволили любой переменной становиться модификатором трафика для любого блока location в конфигурации.
Структура конфигурации NGINX в значительной степени построена на блоках location. В качестве иллюстративного (не буквального) примера посмотрите на такую структуру:
http {
server {
location / { ... }
location /images { ... }
location /api { ... }
location /api/v1/public { ... }
location /api/v1/configuration { ... }
location /api/v1/coffee { ... }
}
}
Такая структура позволяет размещать наиболее значимые и «рабочие» директивы в этих блоках location. Вы можете назначать разные пулы бэкенд‑серверов (upstreams) для маршрутизации, настраивать различные уровни лимитов по скорости и количеству запросов, изменять заголовки в обоих направлениях, настраивать аутентификацию, WAF и другие средства безопасности — и всё это независимо для каждого location.
Мы не можем переопределить эту базовую структуру. Она слишком мощная, стабильная и гибко настраиваемая. Большинству пользователей NGINX она нравится.
С расширением locations до поддержки любых переменных типичная структура локейшенов становится более продвинутой. Например:
http {
server {
location / { ... }
location /images { ... }
location $post_requests { ... }
location $bot_traffic { ... }
location $internal_tests { ... }
location $ai_mcp_queries { ... }
}
}
NGINX вычисляет переменные. Когда переменная оказывается истинной (точнее, «чем угодно, кроме пустой строки или нуля»), вы попадаете в этот location.
Дальше делайте с этим трафиком всё, что хотите.
В NGINX есть хорошо известный модуль map. Отображение переменных в значения становится критически важным для предикатной логики.
Допустим, у вас есть список HTTP‑методов, которые вы хотите считать «истинными» для использования в предикатном локейшене. Все остальные методы должны быть ложными. Используйте такой простой пример в вашей конфигурации:
map $request_method $restricted_methods {
POST 1;
PUT 1;
DELETE 1;
default 0;
}
Устанавливать значение по умолчанию в «0» не обязательно — по умолчанию всегда "", что вычисляется как false. Однако явное объявление может быть полезно при отладке.“»
В этом примере вы теперь можете использовать переменную $restricted_methods в других местах конфигурации, в том числе в предикатных локейшенах.
Конфигурация, полная предикатов, может стать довольно громоздкой.
Если вычисление предиката сложное по своей природе — например, если он читает тело запроса, — производительность может упасть.
По этим причинам делайте структуру локейшенов такой, чтобы она соответствовала вашему приложению.
Предикатные локейшены поддерживают вложенность вместе с классическими локейшенами на основе URL. Мы не предписываем, как именно вы должны их вкладывать. У вашего приложения свои паттерны трафика, которые и подскажут разумный вариант.
В примере ниже мы сначала используем URI, а дальнейшее разделение трафика делаем уже по предикатам:
http {
server {
location /images { ... }
location /api/v1 {
location $restricted_requests {
location $post_requests { ... }
location $bot_traffic { ... }
}
location $internal_tests { ... }
location $ai_mcp_queries { ... }
}
}
}
Как альтернативный подход, вы можете сначала определить предикаты, а обычные локейшены разместить на следующем уровне:
http {
server {
location $public_methods { ... }
location $restricted_methods {
location /api/v1/private {
location $internal_ips { ... }
location $bot_traffic { ... }
}
location /api { ... }
location /wp-admin { ... }
}
}
}
Предикаты изначально спроектированы так, чтобы работать с другими новыми возможностями NGINX — ранним чтением тела HTTP‑запроса и встроенным разбором JSON.
JSON — стандартный формат для современных API. JSONPath — стандарт для поиска значений.
Теперь вы можете задавать переменные на основе отдельных полей и использовать их как предикаты в локейшенах.
Для примера давайте маршрутизировать трафик на основе единицы или нуля в поле «vip» вот в таком теле JSON:
{
"order_id": "1042",
"item": "latte",
"size": "medium",
"user": {
"name": "Nick",
"params": {
"vip": 1
}
}
}
Мы используем следующую конфигурацию NGINX:
events { }
http {
client_body_early_read on; # Необходимо включить для раннего чтения тела
json_set $vip $request_body user.params.vip;
server {
location $vip {
return 200 "VIP usern";
}
location / {
return 200 "Regular user, applying restrictionsn";
# limit_req ...;
}
}
}
Не забудьте включить раннее чтение тела запроса с помощью client_body_early_read.
Протестируем с помощью curl:
nick:~$ curl -X POST -d '{"order_id":"1042","item":"latte","size":"medium","user":{"name":"Somebody","params":{"vip":0}}}' 127.1:8085
Regular user, applying restrictions
nick:~$ curl -X POST -d '{"order_id":"1042","item":"latte","size":"medium","user":{"name":"Nick","params":{"vip":1}}}' 127.1:8085
VIP user
Эта конфигурация демонстрирует то, чего раньше не было: простоту. Мы использовали стандартные для индустрии инструменты, создали переменную и напрямую по ней маршрутизировали.
Разбор JSON и установка переменных не ограничены телом запроса. Вы можете взять любую переменную NGINX, например HTTP‑заголовок или JWT, в качестве источника и распарсить её.
Что ещё можно сделать с этим примером маршрутизации? Отправить трафик на разные upstream‑серверы, ограничить его по скорости, количеству запросов или IP‑адресам. Изменить заголовки и полезную нагрузку. Применить ограничения на основе содержимого, включить или отключить application firewall. Весь набор возможностей NGINX теперь доступен через предельно простой интерфейс.
NJS умеет выполнять множество функций. Он может полностью взять на себя слой маршрутизации NGINX. Однако если злоупотреблять NJS в конфигурации NGINX, она может стать громоздкой. Кроме того, до появления предикатов было сложно «выйти» из NJS обратно в локейшены NGINX. Нашим пользователям приходилось писать мегабайты кода на NJS только ради маршрутизации.
С предикатами NJS упрощается.
В следующем примере мы подсчитаем количество слов в теле HTTP‑запроса, примем решение, не слишком ли длинный запрос, и по‑разному направим трафик на основе этого решения. Мы используем директиву client_body_early_read, чтобы переменная $request_body создавалась на раннем этапе обработки, применим JavaScript для подсчёта слов и установим предикат $many_words. Затем используем его в директиве location.
JavaScript‑файл http.js:
function counter(r) {
const words = r.variables['request_body'].trim().split(/s+/).length;
if (words > 10) {
return 1;
}
return 0;
}
export default {counter};
Конфигурационный файл NGINX nginx.conf:
events { }
http {
client_body_early_read on;
js_import /path/to/conf/http.js;
js_engine qjs;
js_set $many_tokens http.counter;
server {
location $many_tokens {
return 413 "Request body has too many tokensn";
}
location / {
return 200 "Request is small, OKn";
}
}
}
Тестирование с помощью curl:
nick:~$ curl -X POST -d "a b c d e f g h j k l" 127.1:80
Request body has too many tokens
nick:~$ curl -X POST -d "a b c d" 127.1:80
Request is small, OK
Как видите, мы избежали создания сложного набора редиректов и именованных локейшенов, штатно задействовали все возможности nginx через прямое использование директив location и применили всю мощь JavaScript для конкретной небольшой задачи.
Мы работаем над добавлением встроенной поддержки сложной условной логики внутри NGINX. Цель — упростить обработку разнообразных сценариев трафика с точностью и эффективностью, сохраняя конфигурацию nginx простой и надёжной.
Вы сможете задавать сложные логические условия, очень похожие на текущую директиву «if», но без её оговорок и ограничений.
Эта возможность будет доступна в виде отдельной директивы, которая вычисляется в true/false в зависимости от условия. Вы сможете использовать её в предикатных локейшенах или в других местах, где нужна логика [1] true/false.
Если ваша конфигурация насыщена предикатами, используйте следующие рекомендации:
Создавайте catch‑all локейшены. В стандартных конфигурациях обычный блок «location /» имеет смысл только на верхнем уровне вложенности. С предикатами он имеет смысл на любом уровне вложенности как fallback/catch‑all. Размещайте его в конце блока.
Ограничивайте раннее чтение тела запроса только теми участками, где это действительно нужно. Большие тела запросов требуют много памяти [2] и CPU для обработки. Директива client_body_early_read поддерживает переменные. Используйте предикаты по HTTP‑заголовкам или URL, чтобы включать её выборочно. Конечно, когда это возможно.
Обращайте особое внимание [3] на порядок предикатов в конфигурации. Из соображений производительности размещайте простые и часто срабатывающие предикатные локейшены вверху списка, а более сложные — ближе к низу.
Называйте предикаты осмысленно, чтобы позже вы могли эффективно их отслеживать и отлаживать.
Используйте специальные форматы логов для отслеживания переменных. Ваши логи могут показывать значения нескольких переменных в одной строке. Это поможет при отладке.
Теперь NGINX позволяет маршрутизировать трафик практически по чему угодно. Новые фичи гармонично работают вместе:
предикатные локейшены;
раннее чтение тела запроса;
встроенный разбор JSON.
Все эти возможности — строительные блоки. Они бесшовно работают с остальной частью NGINX.
Мы не предписываем, как должно выглядеть ваше приложение, как организовать конфигурацию и как ею управлять. С помощью этих универсальных функций и примеров вы можете создать собственный прокси и балансировщик нагрузки, подходящий практически под любой паттерн трафика.
Смотрите справочную документацию на nginx.org [4]:
NGINX Location Blocks: https://nginx.org/en/docs/http/ngx_http_core_module.html#location [5]
NGINX JSON Module: https://nginx.org/en/docs/http/ngx_http_json_module.html [6]
NGINX client_body_early_read Directive: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_early_read [7]
NGINX 1.31.5 Release Blog: https://blog.nginx.org/blog/nginx-1-31-5-control‑api‑predicate‑locations‑early‑body‑inspection‑and‑more [8]
Change Log for NGINX: https://nginx.org/en/CHANGES [9]
Примечание 1: при написании оригинала этого поста искусственный интеллект [10] не пострадал.
Примечание 2: этот перевод блог‑поста с blog.nginx.com [11] выполнен ИИ, потом вычитан и отредактирован лично автором.
Автор: LEETE
Источник [12]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/35230
URLs in this post:
[1] логика: http://www.braintools.ru/article/7640
[2] памяти: http://www.braintools.ru/article/4140
[3] внимание: http://www.braintools.ru/article/7595
[4] nginx.org: http://nginx.org
[5] https://nginx.org/en/docs/http/ngx_http_core_module.html#location: https://nginx.org/en/docs/http/ngx_http_core_module.html#location
[6] https://nginx.org/en/docs/http/ngx_http_json_module.html: https://nginx.org/en/docs/http/ngx_http_json_module.html
[7] https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_early_read: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_early_read
[8] https://blog.nginx.org/blog/nginx-1-31-5-control‑api‑predicate‑locations‑early‑body‑inspection‑and‑more: https://blog.nginx.org/blog/nginx-1-31-5-control-api-predicate-locations-early-body-inspection-and-more
[9] https://nginx.org/en/CHANGES: https://nginx.org/en/CHANGES
[10] интеллект: http://www.braintools.ru/article/7605
[11] blog.nginx.com: http://blog.nginx.com
[12] Источник: https://habr.com/ru/articles/1080058/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1080058
Нажмите здесь для печати.