sorted-args: Нормализация параметров HTTP querystring для NGINX
Требует подписки Pro плана (или выше) на GetPageSpeed NGINX Extras.
Установка
Вы можете установить этот модуль в любой дистрибутив на базе RHEL, включая, но не ограничиваясь:
- RedHat Enterprise Linux 7, 8, 9 и 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-sorted-args
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-sorted-args
Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:
load_module modules/ngx_http_sorted_args.so;
Этот документ описывает nginx-module-sorted-args v3.0.0, выпущенный 31 декабря 2025 года.
Мощный модуль Nginx, который нормализует параметры запроса HTTP, сортируя их в алфавитном порядке. Этот модуль предоставляет последовательное, каноническое представление строк запроса независимо от исходного порядка параметров, что делает его идеальным для генерации ключей кэша, дедупликации запросов и нормализации URL.
Обзор
Разные URL с одинаковыми параметрами запроса в разном порядке будут производить одну и ту же нормализованную строку запроса:
/index.php?b=2&a=1&c=3/index.php?b=2&c=3&a=1/index.php?c=3&a=1&b=2/index.php?c=3&b=2&a=1
Все вышеперечисленные варианты будут производить одну и ту же нормализованную строку запроса: a=1&b=2&c=3
Эта нормализация доступна через переменную $sorted_args, которая может использоваться в ключах кэша, логировании и других контекстах Nginx.
Особенности
- ✅ Естественная сортировка параметров запроса по ключу, затем по значению (например,
item2<item10) - ✅ Удаление пустых значений — параметры, такие как
?a=, автоматически удаляются - ✅ Режим черного списка (
sorted_args_ignore_list) для исключения конкретных параметров из отсортированного вывода - ✅ Режим белого списка (
sorted_args_allow_list) для сохранения только конкретных параметров, исключая все остальные - ✅ Шаблоны с подстановочными знаками — используйте
utm_*, чтобы соответствовать всем параметрам UTM,*_idдля суффиксов - ✅ Дедупликация (
sorted_args_dedupe) — сохраняйте только первое или последнее вхождение дублирующихся ключей - ✅ Необязательная перезапись
$argsдля автоматической замены оригинальной строки запроса на отсортированные аргументы - ✅ Конфигурация на уровне location с наследованием от серверных и основных контекстов
- ✅ Эффективная реализация с использованием нативной сортировки очереди Nginx
- ✅ Регистронезависимое соответствие имен параметров для фильтрации
- ✅ Обнаружение дубликатов в списках фильтров
Конфигурация
Переменные
$sorted_args
Возвращает параметры строки запроса, отсортированные в алфавитном порядке по имени параметра, затем по значению. Параметры соединяются с помощью & и сохраняют свое оригинальное кодирование URL.
Пример:
Запрос: /page?zebra=1&apple=2&banana=3
$sorted_args: apple=2&banana=3&zebra=1
Поведение:
- Пустая строка запроса возвращает пустую строку
- Параметры без значений (например, ?param) включаются как param
- Параметры с пустыми значениями (например, ?param=) автоматически удаляются
- Несколько значений для одного и того же параметра сортируются индивидуально
- Естественная сортировка: p=1, p=2, p=10 сортируются правильно (не p=1, p=10, p=2)
- Регистронезависимая сортировка для имен параметров
Директивы
sorted_args_ignore_list
Синтаксис: sorted_args_ignore_list pattern [pattern ...];
По умолчанию: нет
Контекст: http, server, location, if
Описание:
Указывает один или несколько шаблонов для исключения из переменной $sorted_args (режим черного списка). Это полезно для удаления параметров, нарушающих кэш (таких как временные метки, номера версий или идентификаторы отслеживания), из ключей кэша, сохраняя при этом другие параметры.
Типы шаблонов:
- name — точное совпадение (регистронезависимое)
- name* — совпадение по префиксу (совпадает с name, name_foo, name123 и т.д.)
- *name — совпадение по суффиксу (совпадает с foo_name, bar_name и т.д.)
- *name* — совпадение по содержимому (совпадает с любым параметром, содержащим name)
Дублирующиеся шаблоны в списке автоматически удаляются.
Пример:
location /api {
# Фильтруем точные имена и все параметры отслеживания utm_*
sorted_args_ignore_list timestamp version _ utm_* fb_*;
proxy_cache_key "$uri$sorted_args";
proxy_pass http://backend;
}
В этом примере запросы, такие как /api?user=123×tamp=1234567890&utm_source=google&utm_medium=cpc, будут производить $sorted_args как user=123, с отфильтрованными timestamp и всеми параметрами UTM.
sorted_args_allow_list
Синтаксис: sorted_args_allow_list pattern [pattern ...];
По умолчанию: нет
Контекст: http, server, location, if
Описание:
Указывает один или несколько шаблонов для сохранения в переменной $sorted_args (режим белого списка). Все параметры, не соответствующие ни одному шаблону, будут исключены. Это полезно, когда вы хотите строго контролировать, какие параметры запроса разрешены для кэширования.
Типы шаблонов:
- name — точное совпадение (регистронезависимое)
- name* — совпадение по префиксу (совпадает с name, name_foo, name123 и т.д.)
- *name — совпадение по суффиксу (совпадает с foo_name, bar_name и т.д.)
- *name* — совпадение по содержимому (совпадает с любым параметром, содержащим name)
Когда одновременно настроены sorted_args_allow_list и sorted_args_ignore_list, сначала применяется белый список (сохраняются только разрешенные параметры), затем черный список для фильтрации любых оставшихся нежелательных параметров.
Пример:
location /api {
# Разрешаем только параметры пагинации и сортировки
sorted_args_allow_list page* sort* limit;
proxy_cache_key "$uri$sorted_args";
proxy_pass http://backend;
}
В этом примере запрос, такой как /api?page=1&page_size=10&sort=asc×tamp=123, будет производить $sorted_args как limit=10&page=1&page_size=10&sort=asc. Параметр timestamp отбрасывается, потому что он не соответствует ни одному шаблону.
sorted_args_overwrite
Синтаксис: sorted_args_overwrite on | off;
По умолчанию: off
Контекст: http, server, location, if
Описание:
Когда включено, эта директива автоматически перезаписывает встроенную переменную $args отсортированными (и, возможно, отфильтрованными) аргументами запроса. Это полезно, когда вы хотите, чтобы все последующие обработки (прокси, логирование, перенаправления) использовали нормализованную строку запроса без явного указания $sorted_args.
Перезапись происходит на этапе переписывания, поэтому все последующие этапы будут видеть отсортированные аргументы в $args.
Пример:
location /api {
sorted_args_overwrite on;
sorted_args_ignore_list timestamp version;
# $args теперь автоматически отсортированы и отфильтрованы
proxy_pass http://backend$uri?$args;
}
В этом примере запрос к /api?z=1&a=2×tamp=123 будет проксироваться как /api?a=2&z=1 — отсортированный и с отфильтрованным timestamp.
sorted_args_dedupe
Синтаксис: sorted_args_dedupe first | last | off;
По умолчанию: off
Контекст: http, server, location, if
Описание:
Контролирует, как обрабатываются дублирующиеся ключи параметров. Когда несколько параметров имеют одинаковый ключ (например, ?a=1&a=2&a=3), эта директива определяет, какое значение сохранить.
first— сохранять только первое вхождение каждого ключаlast— сохранять только последнее вхождение каждого ключаoff— сохранять все вхождения (поведение по умолчанию)
Это полезно для нормализации URL, где один и тот же параметр может быть указан несколько раз, обеспечивая последовательные ключи кэша.
Пример:
location /search {
sorted_args_dedupe first;
proxy_cache_key "$uri$sorted_args";
proxy_pass http://backend;
}
В этом примере запрос, такой как /search?q=foo&q=bar&q=baz, будет производить $sorted_args как q=foo, сохраняя только первое значение. С sorted_args_dedupe last он бы произвел q=baz.
Примеры использования
Нормализация ключей кэша
Нормализуйте ключи кэша независимо от порядка параметров:
http {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m;
server {
listen 80;
location / {
proxy_cache my_cache;
proxy_cache_key "$scheme$host$uri$sorted_args";
proxy_pass http://backend;
}
}
}
Автоматическая перезапись аргументов
Автоматически переписывайте $args с отсортированными параметрами для всех последующих обработок:
server {
listen 80;
location /api {
sorted_args_overwrite on;
sorted_args_ignore_list timestamp _;
# Все эти теперь используют автоматически отсортированные, отфильтрованные аргументы
proxy_pass http://backend;
# Эквивалентно: proxy_pass http://backend$uri?$sorted_args;
}
}
Фильтрация параметров, нарушающих кэш
Удалите временные метки и параметры отслеживания из ключей кэша:
location /static {
sorted_args_ignore_list _ t timestamp v version;
proxy_cache zone;
proxy_cache_key "$uri$sorted_args";
proxy_pass http://cdn;
}
Режим белого списка (разрешение только определенных параметров)
Когда параметры запроса могут вызывать тяжелую обработку на стороне сервера, используйте белый список, чтобы строго контролировать, какие параметры разрешены для кэширования:
location /search {
# Только эти параметры влияют на ключ кэша; все остальные отбрасываются
sorted_args_allow_list q page limit category;
proxy_cache zone;
proxy_cache_key "$uri$sorted_args";
proxy_pass http://search_backend;
}
В этом примере запросы, такие как /search?q=nginx&page=1&debug=true&nocache=1, будут кэшироваться с использованием только category=&limit=&page=1&q=nginx, эффективно игнорируя любые параметры, нарушающие кэш или отладочные.
Сочетание белого и черного списков
Вы можете использовать обе директивы вместе для более тонкого контроля. Сначала применяется белый список, затем черный список:
location /api {
# Сначала сохраняем только эти параметры
sorted_args_allow_list user_id action page limit timestamp;
# Затем удаляем временную метку из разрешенного набора
sorted_args_ignore_list timestamp;
proxy_cache zone;
proxy_cache_key "$uri$sorted_args";
proxy_pass http://api_backend;
}
Логирование нормализованных строк запросов
Включите отсортированные строки запросов в журналы доступа:
http {
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'args="$args" sorted_args="$sorted_args"';
server {
access_log /var/log/nginx/access.log detailed;
# ...
}
}
Фильтрация на уровне location
Разные локации могут иметь разные списки фильтров:
server {
# По умолчанию: фильтруем общие параметры отслеживания
sorted_args_ignore_list _ utm_source utm_medium utm_campaign;
location /api {
# API: также фильтруем версию и временную метку
sorted_args_ignore_list _ utm_source utm_medium utm_campaign version t;
proxy_pass http://api_backend;
}
location /content {
# Контент: фильтруем только отслеживание
proxy_pass http://content_backend;
}
}
Полный пример
pid logs/nginx.pid;
error_log logs/error.log warn;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'args="$args" sorted_args="$sorted_args"';
access_log logs/access.log main;
proxy_cache_path /tmp/cache
levels=1:2
keys_zone=zone:10m
inactive=10d
max_size=100m;
server {
listen 8080;
server_name localhost;
# Фильтруем параметры отслеживания и нарушающие кэш
location /filtered {
sorted_args_ignore_list v _ time timestamp;
proxy_set_header Host "backend";
proxy_pass http://localhost:8081;
proxy_cache zone;
proxy_cache_key "$uri$sorted_args";
proxy_cache_valid 200 1m;
}
# Используем отсортированные аргументы без фильтрации
location / {
proxy_pass http://localhost:8081;
proxy_cache zone;
proxy_cache_key "$uri$sorted_args";
proxy_cache_valid 200 10m;
}
}
# Сервер для тестирования
server {
listen 8081;
location / {
return 200 "args: $args\nsorted_args: $sorted_args\n";
}
}
}
Как это работает
- Извлечение параметров: Модуль разбирает строку запроса из
r->args, разделяя по&и= - Построение очереди: Каждый параметр сохраняется в структуре очереди с его ключом, значением и полной парой ключ-значение
- Сортировка: Параметры сортируются с использованием функции естественного сравнения:
- Первичная сортировка: имя параметра (регистронезависимо, естественный порядок)
- Вторичная сортировка: полная строка параметра (key=value, естественный порядок)
- Естественный порядок означает, что встроенные числа сравниваются численно:
item2<item10 - Удаление пустых значений: Параметры с
=но без значения (например,?a=) удаляются - Фильтрация белого списка: Если настроен
sorted_args_allow_list, сохраняются только параметры, соответствующие шаблонам - Фильтрация черного списка: Параметры, соответствующие шаблонам в
sorted_args_ignore_list, исключаются - Дедупликация: Если включен
sorted_args_dedupe, сохраняется только первое или последнее вхождение каждого ключа - Реконструкция: Отсортированные, отфильтрованные параметры соединяются с помощью
&, чтобы сформировать окончательную строку
Тестирование
Этот проект использует Test::Nginx для своего тестового набора, работающего внутри Docker для воспроизводимых сборок.
Предварительные требования
- Docker
Запуск тестов
Запустите полный набор тестов:
make tests
Запустите конкретный файл теста:
make tests T=t/sorted_args.t
Отключите режим HUP для отладки (медленнее, но более изолированно):
make tests HUP=0
Используйте другую версию Nginx:
make tests NGINX_VERSION=release-1.26.2
Откройте интерактивную оболочку в тестовом контейнере для отладки:
make shell
Покрытие тестами
Тестовый набор проверяет:
- ✅ Основная функциональность сортировки
- ✅ Естественная/числовая сортировка (например, p=1, p=2, p=10 в правильном порядке)
- ✅ Параметры, подобные массивам (например, c[]=1&c[]=2)
- ✅ Фильтрация черного списка (sorted_args_ignore_list)
- ✅ Фильтрация белого списка (sorted_args_allow_list)
- ✅ Совместное использование белого и черного списков
- ✅ Шаблоны с подстановочными знаками: префикс (utm_*), суффикс (*_id), содержит (*token*)
- ✅ Дедупликация: sorted_args_dedupe first и last
- ✅ Обработка пустой строки запроса
- ✅ Удаление пустых значений (?a=&b=2 → b=2)
- ✅ Использование ключа кэша
- ✅ Наследование конфигурации на уровне location
- ✅ Директива sorted_args_overwrite
- ✅ Регистронезависимое соответствие параметров (как для белого, так и для черного списков)
- ✅ Параметры без значений против пустых значений
- ✅ Обработка дублирующихся параметров
- ✅ Сохранение специальных символов
- ✅ Неправильные строки запроса (последовательные амперсанды)
- ✅ Параметры с несколькими знаками равенства
- ✅ E2E: $args изменяется перед оценкой ключа кэша (время этапа REWRITE)
- ✅ E2E: Переупорядоченные параметры производят идентичные ключи кэша
- ✅ E2E: Директивы переписывания видят перезаписанный $args
Соображения по производительности
- Отсортированная строка запроса вычисляется один раз за запрос и кэшируется в контексте запроса
- Сортировка использует эффективный алгоритм на основе очереди Nginx
- Фильтрация использует регистронезависимое строковое сравнение
- Выделение памяти происходит из пула запросов, поэтому явная очистка не требуется
Ограничения
- Значения параметров не декодируются/кодируются; оригинальное кодирование сохраняется
- Фильтрация регистронезависима для имен параметров, но сохраняет оригинальный регистр в выводе
- Параметры с пустыми значениями (например,
?a=) всегда удаляются; используйте?a(без знака равенства) для флагов