Como reescrever o Nginx para obter URL limpo de números de página

Como reescrever o Nginx para obter URL limpo de números de página

Recentemente, mudamos do Apache para o Nginx. No Apache costumava ser muito fácil, basta colocar algumas coisas no .htaccess e pronto.

RewriteEngine on
RewriteBase /

# only rewrite if the requested file doesn't exist
RewriteCond %{REQUEST_FILENAME} !-s

# pass the rest of the request into index.php to handle
RewriteRule ^(.*)$ /index.php/$1 [L]

O texto acima foi ótimo para limpar URL e deixar index.php lidar com todas as solicitações. mas no Nginx precisávamos reescrever cada URL exclusivo no bloco de localização. No entanto, isso não é 'automático' como o Apache.

Alguns exemplos do nosso bloco de localização de reescrita

location / {
try_files $uri $uri/ /index.php;
}

location /p {
rewrite ^/p(?:/([a-z_]+))?$ /index.php?p=$1 last;
rewrite ^/p/all_articles/user/(.*)?$ /index.php?p=all_articles&user=$1 last;
try_files $uri $uri/ /index.php;
}

location /about_us {
rewrite ^/about_us /index.php?about_us last;
try_files $uri $uri/ /index.php;
}

location /search {
rewrite ^/search/(.*) /index.php?search=$1;
rewrite ^/search/(.*)/page/(.*)?$ /index.php?search=$1&page=$2 last;
try_files $uri $uri/ /index.php;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

o acima faz um bom trabalho em URL limpo, mas quando precisamos obter páginas, por exemplo

/p/all_articles/user/ABC/page/2

/index.php?p=all_articles&user=ABC&page=2

nós tentamos

rewrite ^/p/all_articles/user/(.*)/pg(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&pg=$2 last;

isso só funciona quando colocamos em um bloco de localização separado

location /page/all_articles {
rewrite ^/p/all_articles/user/(.*)/pg(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&pg=$2 last;
try_files $uri $uri/ /index.php;
}

e quando feito isso, não deixaria

/p/todos_artigos/usuário/ABC

para carregar.

além disso, as páginas de resultados de pesquisa não funcionariam de todo.


outro problema que encontramos está na pasta .htaccess

Order deny,allow
Deny from all
Options -Indexes

No Apache, isso impediria qualquer acesso a essa pasta e arquivos, exceto o script php. Nós tentamos,

location /(data|img)/ {
   deny all;
   return 404;
}

Ele bloqueia o acesso à pasta, mas, se você especificar o nome do arquivo, ele ainda servirá, sem negar o acesso, por exemplo;

/data/backup_01012020.zip no apache .htaccess, apenas alguns usuários tiveram permissão para acessá-lo, enquanto estavam logados. e fora dele, o apache negará qualquer acesso. Mas no nginx, embora dê 404 ao tentar acessar/data/. Mesmo quando você não estiver logado, ele servirá o arquivo backup_01012020.zip imediatamente.

Agora não conseguimos descobrir o que podemos fazer, o que costumava ser moleza com o Apache. Nosso aplicativo é baseado em PHP e index.php é capaz de lidar com todas as solicitações de URL limpas. Poderia ter sido ótimo se o Nginx simplesmente passasse todas as solicitações para indexar e permitisse que ele fosse processado, em vez de muitas reescritas e blocos de localização. Qualquer ajuda seria ótimo.

Responder1

Você pode estar interessado nas perguntas com oreescrever etiqueta, pois contém muitas variações do seu problema.

Sua regra de reescrita do Apache:

RewriteRule ^(.*)$ /index.php/$1 [L]

anexa todo o URI da solicitação a /index.php. Emnginxocaminhodo URI (normalizado) está disponível no$urivariável. Se você também precisar dos argumentos de consulta, poderá usar o$request_uriem vez de.

Uma tradução estrita de suas regras de reescrita seria, portanto:

location / {
    # Size zero static files are served.
    # I don't believe that is an issue.
    try_files $uri /index.php$request_uri;
}
# If no other .php files are accessible a prefix location of '/index.php/'
# is safer.
location /index.php/ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    # Probably duplicates the contents of fastcgi-php.conf
    # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    # include fastcgi_params;
}

Sua denydiretiva sobre o /(data|img)/local não funciona, pois você está usando uma correspondência de prefixo, em vez de uma correspondência de regex:

location ~ ^/(data|img)/ {
   # Only one is required
   deny all;
   # return 404;
}

Responder2

Solução para reescrever

location /search {
rewrite ^/search/(.*)/page/(.*)?$ /index.php?search=$1&page=$2 last;
rewrite ^/search/(.*) /index.php?search=$1 last;
try_files $uri $uri/ /index.php;
}

location /p/all_articles {
rewrite ^/p/all_articles/user/(.*)/page(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&page=$2 last;
rewrite ^/p/all_articles/user/(.*)?$ /index.php?p=all_articles&user=$1 last;
try_files $uri $uri/ /index.php;
}

Observe, tudo que fiz foi trocar linhas. Créditos paraRicardo Smith


Graças aPiotr P. Karwasz, para a outra solução, pode ajudar alguém cujo script é 100% compatível a lidar com URL limpo por conta própria.

location / {
    # Size zero static files are served.
    # I don't believe that is an issue.
    try_files $uri /index.php$request_uri;
}
# If no other .php files are accessible a prefix location of '/index.php/'
# is safer.
location /index.php/ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    # Probably duplicates the contents of fastcgi-php.conf
    # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    # include fastcgi_params;
}

a solução acima é uma boa opção, desde que seu script funcione 100% com URL limpo. Aqui, você não precisa colocar centenas de blocos de localização reescritos, e o nginx anexará todo o URI da solicitação a /index.php, o que é muito interessante e útil, provavelmente esta é a solução real, mas no meu caso meu script não era 100 % compatível com isso. Ainda assim, esta é uma solução boa e inteligente.


Solução para impedir acesso a pastas e arquivos

location ~ ^/(data|img)/ {
   # Only one is required
   deny all;
   # return 404;
}

Créditos paraPiotr P. Karwaszapontou que deny allestava sendo substituído por algo; após limpar o bloqueio do servidor, o problema foi resolvido. Certifique-se também de usar deny all;ou return 404;mas não juntos.

informação relacionada