Cómo reescribir Nginx para obtener una URL limpia de los números de página

Cómo reescribir Nginx para obtener una URL limpia de los números de página

Recientemente, nos mudamos a Nginx desde Apache. En Apache solía ser muy fácil, simplemente colocaba algunas cosas en .htaccess y listo.

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]

Lo anterior fue excelente para limpiar la URL y permitir que index.php maneje todas las solicitudes. pero en Nginx necesitábamos reescribir cada URL única en el bloque de ubicación. Sin embargo, esto no es "automático" como Apache.

Algunos ejemplos de nuestro bloque de ubicación de reescritura

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

lo anterior funciona bien en URL limpias, pero cuando necesitamos obtener páginas, por ejemplo

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

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

hemos tratado

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

esto solo funciona cuando lo colocamos en un bloque de ubicación 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;
}

y al hacerlo no dejaba

/p/todos_artículos/usuario/ABC

cargar.

Además, las páginas de resultados de búsqueda no funcionarían en absoluto.


Otro problema que encontramos está en la carpeta .htaccess.

Order deny,allow
Deny from all
Options -Indexes

En Apache, esto impediría cualquier acceso a esa carpeta y archivos, excepto al script php. Nosotros tratamos,

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

Bloquea el acceso a la carpeta pero, si especifica el nombre del archivo, seguirá funcionando, sin negar el acceso, por ejemplo;

/data/backup_01012020.zip en apache .htaccess, solo ciertos usuarios podían acceder a esto, mientras estaban conectados. y fuera de él, Apache negará cualquier acceso. Pero bajo nginx, aunque da 404 al intentar acceder a /data/. Incluso cuando no haya iniciado sesión, le entregará el archivo backup_01012020.zip de inmediato.

Ahora no podemos entender qué podemos hacer, lo que solía ser pan comido con Apache. Nuestra aplicación está basada en PHP e index.php es capaz de manejar todas las solicitudes de URL limpias. Podría haber sido genial si Nginx simplemente pasara todas las solicitudes al índice y lo dejara manejar en lugar de muchas reescrituras y bloques de ubicación. Cualquier ayuda sería genial.

Respuesta1

Quizás te interesen las preguntas con elreescribir etiqueta, ya que contiene muchas variaciones de su problema.

Su regla de reescritura de Apache:

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

agrega el URI de solicitud completo a /index.php. Ennginxelcaminodel URI (normalizado) está disponible en el$urivariable. Si también necesita los argumentos de la consulta, puede utilizar el$request_urien cambio.

Por lo tanto, una traducción estricta de sus reglas de reescritura sería:

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

Su denydirectiva sobre la /(data|img)/ubicación no funciona, ya que está utilizando una coincidencia de prefijo, en lugar de una coincidencia de expresiones regulares:

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

Respuesta2

Solución para reescribir

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

Fíjate, todo lo que hice fue intercambiar líneas. Créditos paraRichard Smith


Gracias aPiotr P. Karwasz, para la otra solución, podría ayudar a alguien cuyo script sea 100% compatible a manejar una URL limpia por sí solo.

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

La solución anterior es un camino a seguir siempre y cuando su script funcione con una URL limpia al 100%. Aquí, no es necesario colocar cientos de bloques de ubicación de reescritura, y nginx agregará el URI de solicitud completo a /index.php, lo cual es muy interesante y útil, probablemente esta sea la solución real, pero en mi caso mi script no era 100 % compatible con esto. Aún así, esta es una solución buena e inteligente.


Solución para evitar el acceso a carpetas y archivos.

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

Créditos paraPiotr P. KarwaszComo señaló, deny allalgo estaba siendo anulado, al bloquear el servidor limpio resolvió el problema. También asegúrese de usar deny all;o return 404;pero no juntos.

información relacionada