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.so;

Este documento descreve nginx-module-sorted-args v3.0.0 lançado em 31 de dezembro de 2025.


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 query strings, 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 query 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, logs e outros contextos do NGINX.

Test Build

Recursos

  • Ordenação natural dos parâmetros de query 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 curinga — use utm_* para corresponder a todos os parâmetros UTM, *_id para sufixos
  • Deduplicação (sorted_args_dedupe) — mantém 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 diferenciaçã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 da querystring ordenados alfanumericamente por nome de parâmetro, depois por valor. Os parâmetros são unidos com & e mantêm sua codificação de URL original.

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 diferenciaçã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 diferenciação entre maiúsculas e minúsculas) - name* — correspondência por prefixo (corresponde a name, name_foo, name123, etc.) - *name — correspondência por 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 query são permitidos para cache.

Tipos de padrões: - name — correspondência exata (sem diferenciação entre maiúsculas e minúsculas) - name* — correspondência por prefixo (corresponde a name, name_foo, name123, etc.) - *name — correspondência por 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 {
    # Permitir apenas 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 habilitada, esta diretiva sobrescreve automaticamente a variável interna $args com os argumentos de query ordenados (e opcionalmente filtrados). Isso é útil quando você deseja que todo o processamento subsequente (proxy, logging, redirecionamentos) use a querystring normalizada sem referenciar explicitamente $sorted_args.

A sobrescrita ocorre 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 Chave 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 subsequente:

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 parâmetros de timestamp e 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 (Apenas Parâmetros Específicos)

Quando parâmetros de query podem causar processamento pesado 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 cacheadas 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 um controle mais 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;

    # Depois, 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 de 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, dividindo em & 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 diferenciaçã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 reprodutí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 Testes

A suíte de testes verifica: - ✅ Funcionalidade básica de ordenação - ✅ Ordenação natural/númerica (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 curinga: 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 diferenciaçã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 query 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 de REWRITE) - ✅ E2E: Parâmetros reordenados produzem chaves de cache idênticas - ✅ E2E: Diretrizes de reescrita veem $args sobrescrito

Considerações de Desempenho

  • A querystring ordenada é computada uma vez por requisição e armazenada no contexto da requisição
  • A ordenação usa o algoritmo eficiente baseado em fila do NGINX
  • A filtragem usa comparação de strings sem diferenciaçã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/codificados; a codificação original é preservada
  • A filtragem é sem diferenciaçã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