Regra de reescrita do Nginx para substituir o ponto de interrogação da string de consulta por sublinhado

16

Para espelhar um site inteiro como HTML estático,

Eu gostaria de converter URLs como http://example.com/script.php?t=12para http://example.com/script.php_t=12.

O aviso ?no URL está sendo convertido para _.

Isso permitirá que o nginx ou o apache sirva esses arquivos do disco como o HTML bruto que obtivemos e salvamos wget- um arquivo para cada URL - e não como um arquivo PHP.

É possível fazer isso através da reescrita de URL do Nginx?

Arpit Jalan
fonte
Certamente é possível, mas muito estranho. Para que você quer isso?
Alexey Ten
2
Um problema com essa abordagem é que vários parâmetros GET em uma URL podem estar em qualquer ordem e, quando você faz essa conversão, altera a semântica da URL.
Tero Kilkanen 10/03/2015
sua para o arquivamento de um antigo fórum em HTML estático, mas sim ter esse trabalho com http://example.com/script.php?a=1&t=3vai precisar de alguma ação super chique reescrita
Sam Saffron
11
@tero, os URLs da string de consulta estão, na prática, sempre na mesma ordem. Portanto, este não é um problema.
Jeff Atwood
11
@chx é para o arquivamento de um fórum de idade, então o argumento pode ser diferente tcomo f, u, etc.
Arpit Jalan

Respostas:

15

Eu tenho esse trabalho usando try_files:

location / {
    try_files "${uri}_${args}" 404.html;
}

Isso tentará encontrar um arquivo no disco com o nome do padrão que você forneceu com "_" em vez de "?".

A configuração adicional depende de como você salvou arquivos estáticos, como imagens ou folhas de estilo. Você pode adicionar um fallback tentando lê-los sem consultar o disco do formulário da cadeia de caracteres da seguinte maneira:

location / {
    try_files "${uri}_${args}" $uri 404.html;
}
Matthias Bayer
fonte
11
abordagem muito interessante, isso causaria uma possível leitura de disco e "arquivo não encontrado" em todos os possíveis URLs?
Jeff Atwood
From try_files : "Verifica a existência de arquivos na ordem especificada e usa o primeiro arquivo encontrado para processamento de solicitação". Portanto, isso não causará leituras de disco adicionais para os URLs na sua pergunta.
Matthias Bayer
11
ok, se vamos colocá-la em location ~ \.php$nós podemos começar try_filesa trabalhar, mas ele não funciona emlocation /
Jeff Atwood
+1 por exemplo, no uso de chaves :)
Danila Vershinin
4

Algo ao longo das linhas:

location ~ \.php$ {
  # only rewrite URL's with args
  if ($args != '') {
    rewrite .* "${uri}_${args}?" last;
  }
}
Max Gashkov
fonte
Você deixou de fora a ?minha resposta usada.
Chx
Você está correto em relação a?, Quanto à sua resposta - levei algum tempo para testá-lo no servidor real, então não vi o seu até publicar o meu. E o seu reescreverá todos os URLs, mesmo sem argumentos, para variar com "_" o que pode ser indesejável.
Max Gashkov
A solução da Matthias com try_files é realmente mais preferível a isso.
Max Gashkov
podemos fazer isso sem o if, quando especificarmos uma .*cláusula mais estrita no primeiro parâmetro de reescrita. Isso é extremamente útil!
21815 Jeff Atwood
@JeffAtwood Acho que isso não é possível - os padrões de reescrita nginx (assim como a localização) devem ser aplicados a parte de um URL antes apenas da string de consulta.
Max Gashkov 12/03
1

Eu não acho que você será capaz de fazer isso com o vanilla nginx, mas se estiver disposto a instalar o módulo Lua para o nginx ( http://wiki.nginx.org/HttpLuaModule ), você poderá fazê-lo.

server {
    server_name so.dev;
    listen 80;

    location / {

        root /tmp;

        rewrite_by_lua '
            local uri = ngx.var.uri
            local params = ngx.req.get_uri_args(0)

            for key, value in pairs(params) do
                uri = string.format("%s_%s=%s", uri, key, value)
            end

            ngx.req.set_uri(uri)
            ngx.req.set_uri_args({})
        ';

    }
}

Testado localmente e parece fazer o que você está procurando. Se você deseja manter outros parâmetros separados por e comercial, altere o bloco rewrite_by_lua para

local uri = ngx.var.uri
local param_string = ""
local params = ngx.req.get_uri_args(0)
local separator = ""

for key, value in pairs(params) do
    param_string = param_string .. separator .. key .. "=" .. value
    separator = "&"
end

ngx.req.set_uri(uri .. "_" .. param_string)
ngx.req.set_uri_args({})
c17r
fonte
1

Isso funciona no nginx / 1.6.2.

rewrite ^/.*\.php$ "${uri}_${args}";

Mas, pessoalmente, eu usaria a try_filessolução com um fallback para um URI original, se houver .

try_files $uri "${uri}_${args}";

Por exemplo, se você tiver um script.phpdisco, ele tentará primeiro, e depois, se não houver nenhum, será utilizado script.php_t=12. try_filesprecisa de uma versão recente o suficiente do nginx.

E se isso não for suficiente, você pode fazer isso dentro de um if:

return 301 "${uri}_${args}";
sanmai
fonte
Eu gosto disso, mas não podemos obter os try_files pouco para realmente trabalho, ao passo que a reescrita faz trabalho. (bem, se você adicionar um ?para o final de sua reescrita lá assim que os parâmetros de consulta não são adicionados a ele ..)
Jeff Atwood
@JeffAtwood try_filesvai parar $urise houver um bloco de localização correspondente a esse arquivo ou um arquivo para ele (a solicitação sem obter argumentos) - é esse o caso?
AD7six
@JeffAtwood ?não tem efeito visível em arquivos estáticos, você só vê uma consulta extra nos seus logs de acesso; Se você se preocupa com ele, com certeza adicionar um ponto de interrogação
sanmai
0

O wiki diz

Se você especificar um? no final de uma reescrita, o Nginx eliminará os $ args originais (argumentos).

Então, rewrite ^ ${uri}_$args? last;deve funcionar.

chx
fonte
nginx não reiniciar com aquele conjunto de regras -rewrite ^ $uri_$args? last;
Jeff Atwood
Fixo. O $ -bleeds-over-the-variable parece o PHP que eu sei que você simplesmente ama.
chx
mesmo com a versão revista, nginx não consegue reiniciar
Jeff Atwood
0

As respostas sugeridas acima devem funcionar. No entanto, você vê a sensibilidade do seu URL. Como o nginx tenta verificar se o nome do arquivo existe no servidor primeiro, qualquer parâmetro extra o desativará.

http://example.com/script.php?t=12 // works 
http://example.com/script.php?t=12&_utm=twitter // not work

Minha sugestão é deixar o URL como está e encaminhá-lo para o arquivo correto com php. Você tem acesso ao tparâmetro

Ibu
fonte