Перейти к содержанию

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.

Test Build

Особенности

  • Естественная сортировка параметров запроса по ключу, затем по значению (например, 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&timestamp=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&timestamp=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&timestamp=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";
        }
    }
}

Как это работает

  1. Извлечение параметров: Модуль разбирает строку запроса из r->args, разделяя по & и =
  2. Построение очереди: Каждый параметр сохраняется в структуре очереди с его ключом, значением и полной парой ключ-значение
  3. Сортировка: Параметры сортируются с использованием функции естественного сравнения:
  4. Первичная сортировка: имя параметра (регистронезависимо, естественный порядок)
  5. Вторичная сортировка: полная строка параметра (key=value, естественный порядок)
  6. Естественный порядок означает, что встроенные числа сравниваются численно: item2 < item10
  7. Удаление пустых значений: Параметры с = но без значения (например, ?a=) удаляются
  8. Фильтрация белого списка: Если настроен sorted_args_allow_list, сохраняются только параметры, соответствующие шаблонам
  9. Фильтрация черного списка: Параметры, соответствующие шаблонам в sorted_args_ignore_list, исключаются
  10. Дедупликация: Если включен sorted_args_dedupe, сохраняется только первое или последнее вхождение каждого ключа
  11. Реконструкция: Отсортированные, отфильтрованные параметры соединяются с помощью &, чтобы сформировать окончательную строку

Тестирование

Этот проект использует 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=2b=2) - ✅ Использование ключа кэша - ✅ Наследование конфигурации на уровне location - ✅ Директива sorted_args_overwrite - ✅ Регистронезависимое соответствие параметров (как для белого, так и для черного списков) - ✅ Параметры без значений против пустых значений - ✅ Обработка дублирующихся параметров - ✅ Сохранение специальных символов - ✅ Неправильные строки запроса (последовательные амперсанды) - ✅ Параметры с несколькими знаками равенства - ✅ E2E: $args изменяется перед оценкой ключа кэша (время этапа REWRITE) - ✅ E2E: Переупорядоченные параметры производят идентичные ключи кэша - ✅ E2E: Директивы переписывания видят перезаписанный $args

Соображения по производительности

  • Отсортированная строка запроса вычисляется один раз за запрос и кэшируется в контексте запроса
  • Сортировка использует эффективный алгоритм на основе очереди Nginx
  • Фильтрация использует регистронезависимое строковое сравнение
  • Выделение памяти происходит из пула запросов, поэтому явная очистка не требуется

Ограничения

  • Значения параметров не декодируются/кодируются; оригинальное кодирование сохраняется
  • Фильтрация регистронезависима для имен параметров, но сохраняет оригинальный регистр в выводе
  • Параметры с пустыми значениями (например, ?a=) всегда удаляются; используйте ?a (без знака равенства) для флагов