Pular para conteúdo

sorted-args: normalização de parâmetros de querystring HTTP para NGINX

Requer o plano Pro (ou superior) da assinatura GetPageSpeed NGINX Extras.

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e 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

Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:

load_module modules/ngx_http_sorted_args_module.so;

Este documento descreve nginx-module-sorted-args v3.0.1 lançado em 03 de maio de 2026.


Um poderoso módulo Nginx que normaliza os parâmetros de querystring de requisições HTTP, ordenando-os alfanumericamente. Este módulo fornece uma representação consistente e canônica de strings de consulta, independentemente da ordem original dos parâmetros, tornando-o ideal para geração de chaves de cache, deduplicação de requisições e normalização de URLs.

Visão Geral

URLs diferentes com os mesmos parâmetros de consulta em ordens diferentes produzirão a mesma querystring normalizada:

  • /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

Todos os acima produzirão a mesma querystring normalizada: a=1&b=2&c=3

Essa normalização é acessível através da variável $sorted_args, que pode ser usada em chaves de cache, logging e outros contextos do Nginx.

Recursos

  • Ordenação natural dos parâmetros de consulta por chave, depois por valor (ex: item2 < item10)
  • Remoção de valores vazios — parâmetros como ?a= são automaticamente removidos
  • Modo de lista negra (sorted_args_ignore_list) para excluir parâmetros específicos da saída ordenada
  • Modo de lista branca (sorted_args_allow_list) para manter apenas parâmetros específicos, descartando todos os outros
  • Padrões coringa — use utm_* para corresponder a todos os parâmetros UTM, *_id para sufixos
  • Deduplicação (sorted_args_dedupe) — mantenha apenas a primeira ou última ocorrência de chaves duplicadas
  • Sobrescrita opcional de $args para substituir automaticamente a querystring original por args ordenados
  • Configuração em nível de localização com herança dos contextos de servidor e principal
  • Implementação eficiente usando a ordenação de fila nativa do Nginx
  • Correspondência de nomes de parâmetros sem distinção entre maiúsculas e minúsculas para filtragem
  • Detecção de duplicatas em listas de filtro

Configuração

Variáveis

$sorted_args

Retorna os parâmetros de querystring ordenados alfanumericamente por nome de parâmetro, depois por valor. Os parâmetros são unidos com & e mantêm sua codificação original de URL.

Exemplo:

Requisição: /page?zebra=1&apple=2&banana=3
$sorted_args: apple=2&banana=3&zebra=1

Comportamento: - Querystring vazia retorna uma string vazia - Parâmetros sem valores (ex: ?param) são incluídos como param - Parâmetros com valores vazios (ex: ?param=) são automaticamente removidos - Múltiplos valores para o mesmo parâmetro são ordenados individualmente - Ordenação natural: p=1, p=2, p=10 são ordenados corretamente (não p=1, p=10, p=2) - Ordenação sem distinção entre maiúsculas e minúsculas para nomes de parâmetros

Diretivas

sorted_args_ignore_list

Sintaxe: sorted_args_ignore_list pattern [pattern ...];

Padrão: nenhum

Contexto: http, server, location, if

Descrição:

Especifica um ou mais padrões a serem excluídos da variável $sorted_args (modo de lista negra). Isso é útil para remover parâmetros que quebram o cache (como timestamps, números de versão ou IDs de rastreamento) das chaves de cache, preservando outros parâmetros.

Tipos de padrões: - name — correspondência exata (sem distinção entre maiúsculas e minúsculas) - name* — correspondência de prefixo (corresponde a name, name_foo, name123, etc.) - *name — correspondência de sufixo (corresponde a foo_name, bar_name, etc.) - *name* — correspondência de contém (corresponde a qualquer parâmetro contendo name)

Padrões duplicados na lista são automaticamente removidos.

Exemplo:

location /api {
    # Filtrar nomes exatos e todos os parâmetros de rastreamento utm_*
    sorted_args_ignore_list timestamp version _ utm_* fb_*;

    proxy_cache_key "$uri$sorted_args";
    proxy_pass http://backend;
}

Neste exemplo, requisições como /api?user=123&timestamp=1234567890&utm_source=google&utm_medium=cpc produzirão $sorted_args como user=123, com timestamp e todos os parâmetros UTM filtrados.

sorted_args_allow_list

Sintaxe: sorted_args_allow_list pattern [pattern ...];

Padrão: nenhum

Contexto: http, server, location, if

Descrição:

Especifica um ou mais padrões para manter na variável $sorted_args (modo de lista branca). Todos os parâmetros que NÃO corresponderem a nenhum padrão serão excluídos. Isso é útil quando você deseja controlar estritamente quais parâmetros de consulta são permitidos para cache.

Tipos de padrões: - name — correspondência exata (sem distinção entre maiúsculas e minúsculas) - name* — correspondência de prefixo (corresponde a name, name_foo, name123, etc.) - *name — correspondência de sufixo (corresponde a foo_name, bar_name, etc.) - *name* — correspondência de contém (corresponde a qualquer parâmetro contendo name)

Quando tanto sorted_args_allow_list quanto sorted_args_ignore_list estão configurados, a lista branca é aplicada primeiro (mantendo apenas os parâmetros permitidos), depois a lista negra é aplicada para filtrar quaisquer parâmetros indesejados restantes.

Exemplo:

location /api {
    # Apenas permitir parâmetros de paginação e ordenação
    sorted_args_allow_list page* sort* limit;

    proxy_cache_key "$uri$sorted_args";
    proxy_pass http://backend;
}

Neste exemplo, uma requisição como /api?page=1&page_size=10&sort=asc&timestamp=123 produzirá $sorted_args como limit=10&page=1&page_size=10&sort=asc. O parâmetro timestamp é descartado porque não corresponde a nenhum padrão.

sorted_args_overwrite

Sintaxe: sorted_args_overwrite on | off;

Padrão: off

Contexto: http, server, location, if

Descrição:

Quando habilitado, esta diretiva sobrescreve automaticamente a variável interna $args com os argumentos de consulta ordenados (e opcionalmente filtrados). Isso é útil quando você deseja que todo o processamento a montante (proxy, logging, redirecionamentos) use a querystring normalizada sem referenciar explicitamente $sorted_args.

A sobrescrita acontece durante a fase de reescrita, então todas as fases subsequentes verão os argumentos ordenados em $args.

Exemplo:

location /api {
    sorted_args_overwrite on;
    sorted_args_ignore_list timestamp version;

    # $args agora é automaticamente ordenado e filtrado
    proxy_pass http://backend$uri?$args;
}

Neste exemplo, uma requisição para /api?z=1&a=2&timestamp=123 será proxyada como /api?a=2&z=1 — ordenada e com timestamp filtrado.

sorted_args_dedupe

Sintaxe: sorted_args_dedupe first | last | off;

Padrão: off

Contexto: http, server, location, if

Descrição:

Controla como as chaves de parâmetros duplicados são tratadas. Quando múltiplos parâmetros têm a mesma chave (ex: ?a=1&a=2&a=3), esta diretiva determina qual valor manter.

  • first — mantém apenas a primeira ocorrência de cada chave
  • last — mantém apenas a última ocorrência de cada chave
  • off — mantém todas as ocorrências (comportamento padrão)

Isso é útil para normalizar URLs onde o mesmo parâmetro pode ser especificado várias vezes, garantindo chaves de cache consistentes.

Exemplo:

location /search {
    sorted_args_dedupe first;

    proxy_cache_key "$uri$sorted_args";
    proxy_pass http://backend;
}

Neste exemplo, uma requisição como /search?q=foo&q=bar&q=baz produzirá $sorted_args como q=foo, mantendo apenas o primeiro valor. Com sorted_args_dedupe last, produziria q=baz.

Exemplos de Uso

Normalização Básica de Chaves de Cache

Normalize chaves de cache independentemente da ordem dos parâmetros:

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;
        }
    }
}

Sobrescrita Automática de Args

Reescreva automaticamente $args com parâmetros ordenados para todo o processamento a montante:

server {
    listen 80;

    location /api {
        sorted_args_overwrite on;
        sorted_args_ignore_list timestamp _;

        # Todos esses agora usam args ordenados e filtrados automaticamente
        proxy_pass http://backend;
        # Equivalente a: proxy_pass http://backend$uri?$sorted_args;
    }
}

Filtrando Parâmetros que Quebram o Cache

Remova timestamps e parâmetros de rastreamento das chaves de cache:

location /static {
    sorted_args_ignore_list _ t timestamp v version;

    proxy_cache zone;
    proxy_cache_key "$uri$sorted_args";
    proxy_pass http://cdn;
}

Modo de Lista Branca (Somente Parâmetros Específicos)

Quando parâmetros de consulta podem causar processamento intenso no lado do servidor, use uma lista branca para controlar estritamente quais parâmetros são permitidos para cache:

location /search {
    # Apenas esses parâmetros afetam a chave de cache; todos os outros são descartados
    sorted_args_allow_list q page limit category;

    proxy_cache zone;
    proxy_cache_key "$uri$sorted_args";
    proxy_pass http://search_backend;
}

Neste exemplo, requisições como /search?q=nginx&page=1&debug=true&nocache=1 serão armazenadas em cache usando apenas category=&limit=&page=1&q=nginx, ignorando efetivamente quaisquer parâmetros que quebram o cache ou de depuração.

Combinando Lista Branca e Lista Negra

Você pode usar ambas as diretivas juntas para controle detalhado. A lista branca é aplicada primeiro, depois a lista negra:

location /api {
    # Primeiro, mantenha apenas esses parâmetros
    sorted_args_allow_list user_id action page limit timestamp;

    # Em seguida, remova timestamp do conjunto permitido
    sorted_args_ignore_list timestamp;

    proxy_cache zone;
    proxy_cache_key "$uri$sorted_args";
    proxy_pass http://api_backend;
}

Registrando Querystrings Normalizadas

Inclua querystrings ordenadas nos logs de acesso:

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;
        # ...
    }
}

Filtragem Específica por Localização

Diferentes localizações podem ter diferentes listas de filtro:

server {
    # Padrão: filtrar parâmetros de rastreamento comuns
    sorted_args_ignore_list _ utm_source utm_medium utm_campaign;

    location /api {
        # API: também filtrar versão e timestamp
        sorted_args_ignore_list _ utm_source utm_medium utm_campaign version t;
        proxy_pass http://api_backend;
    }

    location /content {
        # Conteúdo: apenas filtrar rastreamento
        proxy_pass http://content_backend;
    }
}

Exemplo Completo

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;

        # Filtrar parâmetros de rastreamento e que quebram o cache
        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;
        }

        # Usar args ordenados sem filtragem
        location / {
            proxy_pass http://localhost:8081;

            proxy_cache zone;
            proxy_cache_key "$uri$sorted_args";
            proxy_cache_valid 200 10m;
        }
    }

    # Servidor backend para testes
    server {
        listen       8081;

        location / {
            return 200 "args: $args\nsorted_args: $sorted_args\n";
        }
    }
}

Como Funciona

  1. Extração de Parâmetros: O módulo analisa a querystring de r->args, separando por & e =
  2. Construção de Fila: Cada parâmetro é armazenado em uma estrutura de fila com sua chave, valor e par chave-valor completo
  3. Ordenação: Os parâmetros são ordenados usando uma função de comparação natural:
  4. Ordenação primária: nome do parâmetro (sem distinção entre maiúsculas e minúsculas, ordem natural)
  5. Ordenação secundária: string completa do parâmetro (key=value, ordem natural)
  6. Ordem natural significa que números embutidos são comparados numericamente: item2 < item10
  7. Remoção de Valores Vazios: Parâmetros com = mas sem valor (como ?a=) são removidos
  8. Filtragem de Lista Branca: Se sorted_args_allow_list estiver configurado, apenas parâmetros que correspondem a padrões são mantidos
  9. Filtragem de Lista Negra: Parâmetros que correspondem a padrões em sorted_args_ignore_list são excluídos
  10. Deduplicação: Se sorted_args_dedupe estiver habilitado, apenas a primeira ou última ocorrência de cada chave é mantida
  11. Reconstrução: Os parâmetros ordenados e filtrados são unidos com & para formar a string final

Testes

Este projeto usa Test::Nginx para sua suíte de testes, rodando dentro do Docker para builds reproduzíveis.

Pré-requisitos

  • Docker

Executando Testes

Execute a suíte de testes completa:

make tests

Execute um arquivo de teste específico:

make tests T=t/sorted_args.t

Desative o modo HUP para depuração (mais lento, mas mais isolado):

make tests HUP=0

Use uma versão diferente do Nginx:

make tests NGINX_VERSION=release-1.26.2

Abra um shell interativo no contêiner de teste para depuração:

make shell

Cobertura de Teste

A suíte de testes verifica: - ✅ Funcionalidade básica de ordenação - ✅ Ordenação natural/numerica (ex: p=1, p=2, p=10 na ordem correta) - ✅ Parâmetros semelhantes a arrays (ex: c[]=1&c[]=2) - ✅ Filtragem de lista negra (sorted_args_ignore_list) - ✅ Filtragem de lista branca (sorted_args_allow_list) - ✅ Uso combinado de lista branca e lista negra - ✅ Padrões coringa: prefixo (utm_*), sufixo (*_id), contém (*token*) - ✅ Deduplicação: sorted_args_dedupe first e last - ✅ Tratamento de querystring vazia - ✅ Remoção de valores vazios (?a=&b=2b=2) - ✅ Uso de chave de cache - ✅ Herança de configuração em nível de localização - ✅ Diretiva sorted_args_overwrite - ✅ Correspondência de parâmetros sem distinção entre maiúsculas e minúsculas (tanto lista branca quanto lista negra) - ✅ Parâmetros sem valores vs valores vazios - ✅ Tratamento de parâmetros duplicados - ✅ Preservação de caracteres especiais - ✅ Strings de consulta malformadas (ampersands consecutivos) - ✅ Parâmetros com múltiplos sinais de igual - ✅ E2E: $args é modificado antes da avaliação da chave de cache (tempo da fase REWRITE) - ✅ E2E: parâmetros reordenados produzem chaves de cache idênticas - ✅ E2E: diretivas de reescrita veem $args sobrescrito

Considerações de Desempenho

  • A querystring ordenada é computada uma vez por requisição e armazenada em cache no contexto da requisição
  • A ordenação usa o algoritmo eficiente baseado em fila do Nginx
  • A filtragem usa comparação de string sem distinção entre maiúsculas e minúsculas
  • A alocação de memória é feita a partir do pool de requisições, portanto, nenhuma limpeza explícita é necessária

Limitações

  • Os valores dos parâmetros não são decodificados/recodificados; a codificação original é preservada
  • A filtragem é sem distinção entre maiúsculas e minúsculas para nomes de parâmetros, mas preserva a caixa original na saída
  • Parâmetros com valores vazios (ex: ?a=) são sempre removidos; use ?a (sem igual) para flags