nginx try_files processado duas vezes e falha se o conjunto de fallback de erro

3

Eu tenho uma configuração de bloco de localização para capturar todas as solicitações de arquivo e enviá-las para PHP-FPM :

location  / {
    try_files  $uri /routing.php?$args;
    fastcgi_pass   unix:/opt/local/var/run/php54/php-fpm-www.sock;
    include       /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}

Isso funciona e passa corretamente a solicitação para PHP-FPM para o arquivo php exato que foi solicitado ou com routing.php definido como o script a ser executado.

Eu tentei adicionar uma página de erro, para que, se o arquivo de roteamento fosse removido ou não estivesse disponível, a página de erro seria mostrada em vez da página de erro padrão do Nginx:

location  / {
    try_files $uri /routing.php?$args /50x_static.html;
    fastcgi_pass   unix:/opt/local/var/run/php54/php-fpm-www.sock;
    include       /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}

Isso impede que o arquivo routing.php seja exibido e a página 50x_static.html é mostrada. Solicitações para um arquivo PHP existente ainda funcionam, por exemplo, indo para a URL /dynamic.php

Eu percebo que o último parâmetro em um comando try_files é um pouco mágico:

In the event that no file is found, an internal redirect to the last parameter is invoked. Do note that only the last parameter causes an internal redirect, former ones just sets the internal URI pointer. The last parameter is the fallback URI and must exist, or else an internal error will be raised.

Ao investigar por que a error_page quebrou a configuração, percebi que para a configuração que funciona (sem a página de erro estático), o Nginx parece estar correspondendo à solicitação duas vezes de acordo com o log de regravação do Nginx ao tentar obter a raiz URL "/":

"^/proxy/(\d+)/(\w+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/staticImage/(\w+)/(.+)\.([^\.]*)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(\w+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/staticImage/(\w+)/(.+)\.([^\.]*)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"

i.e. a solicitação é enviada como / , a try_files não veicula o arquivo e, portanto, reescreve a solicitação de / para /routing.php e, em seguida, reprocessa a solicitação.

Por que os arquivos try não veiculam o arquivo routing.php na primeira passagem? Ele existe e é acessível, caso contrário, não seria servido na segunda vez.

EDITAR

Configuração não relacionada removida.

    
por Danack 14.05.2013 / 19:22

2 respostas

3

A documentação que você citou explicitamente diz "um redirecionamento interno para o último parâmetro é chamado". O redirecionamento interno é tratado da mesma forma que a solicitação inicial proveniente do cliente - isso inclui o processamento das instruções rewrite no nível do servidor, que você vê no log. No entanto, se qualquer outro parâmetro try_files , exceto o último, corresponder a um arquivo existente, a solicitação será tratada usando a configuração location na qual a instrução try_files está localizada e não haverá correspondência correspondente.

Quanto às suas regras, você tentou apenas omitir $args em try_files ?

location  / {
    try_files $uri /routing.php /50x_static.html;
    fastcgi_pass   unix:/opt/local/var/run/php54/php-fpm-www.sock;
    include       /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}

Observe que $uri não contém $args também; Os parâmetros de consulta ainda serão passados para o backend FastCGI através do parâmetro QUERY_STRING , que é presumivelmente definido em seu fastcgi.conf :

fastcgi_param QUERY_STRING    $query_string;

E se nem $uri nem /routing.php estiverem presentes como arquivos, a solicitação será redirecionada para /50x_static.html e processada de acordo com a seção location = /50x_static.html em sua configuração (mas uma segunda iteração de tentativas de reconfiguração ainda será realizada, porque suas regras de reescrita são colocadas no nível do servidor).

Um detalhe muito suspeito da sua configuração é que você está passando todos os arquivos pelo PHP, independentemente da extensão do arquivo - isso é muito incomum e pode causar problemas de segurança devido à execução do código PHP em um arquivo onde não era esperado. / p>     

por 17.05.2013 / 21:20
0

Sergey estava correto; adicionar $args a um comando try_files pára a correspondência do arquivo e, portanto, envia Nginx round em outro loop de processamento, que é ímpar, já que é isso que o Nginx exemplo diz para fazer .

Se você seguir o exemplo exatamente com:

try_files $uri $uri/ /index.php?q=$uri&$args;

Se $uri e $uri/ não existirem, o Nginx passará para o último parâmetro mágico. Ele nem sequer tenta corresponder ao arquivo e, em vez disso, reprocessa a solicitação, definindo o novo caminho para /index.php e o $args para agora ser q=$uri&$args .

Por outro lado, se você tiver outro valor em try_files após index.php, por exemplo

try_files $uri $uri/ /index.php?q=$uri&$args /50x_static.html;

O Nginx procura por um arquivo chamado /index.php?q=$uri&$args e obviamente não existe, e assim ele move para o /50x_static.html e reprocessa isso.

Porque $uri é reescrito quando o Nginx reprocessa a solicitação, evitando que isso precise de algumas alterações sutis. Se você configurou sua configuração para ser assim:

set $originalURI  $uri;
try_files $uri $uri/ /index.php  /50x_static.html;
fastcgi_param  QUERY_STRING  q=$originalURI&$query_string;

O arquivo que o Nginx procura é /index.php , que é o nome correto, então o nginx irá parar o processamento lá. Nós temos que copiar a variável $uri como o try_files modifica e então seria apenas /index.php se nós a usássemos após o try_files.

    
por 17.05.2013 / 22:50

Tags