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

sorted-args: Нормализация параметров запроса HTTP для NGINX

Установка для Debian/Ubuntu

Эти документы относятся к пакету APT nginx-module-sorted-args, предоставляемому репозиторием GetPageSpeed Extras.

  1. Настройте APT-репозиторий, как описано в настройке APT-репозитория.
  2. Установите модуль:
sudo apt-get update
sudo apt-get install nginx-module-sorted-args
Показать дистрибутивы и архитектуры
| Дистрибутив | Версия            | Компонент   | Архитектуры    |
|-------------|-------------------|-------------|-----------------|
| debian      | bookworm          | main        | amd64, arm64    |
| debian      | bookworm-mainline | main        | amd64, arm64    |
| debian      | trixie            | main        | amd64, arm64    |
| debian      | trixie-mainline   | main        | amd64, arm64    |
| ubuntu      | focal             | main        | amd64, arm64    |
| ubuntu      | focal-mainline    | main        | amd64, arm64    |
| ubuntu      | jammy             | main        | amd64, arm64    |
| ubuntu      | jammy-mainline    | main        | amd64, arm64    |
| ubuntu      | noble             | main        | amd64, arm64    |
| ubuntu      | noble-mainline    | main        | amd64, arm64    |

Мощный модуль 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

Все вышеперечисленные URL создадут одну и ту же нормализованную строку запроса: 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 для автоматической замены исходной строки запроса на отсортированные аргументы
  • Конфигурация на уровне локации с наследованием от серверного и основного контекстов
  • Эффективная реализация с использованием родной сортировки очереди 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;
        # ...
    }
}

Фильтрация На Основе Местоположения

Разные местоположения могут иметь разные списки фильтров:

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

Учет производительности

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

Ограничения

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