
Mi pila:
- LÁMPARA
- Apache/2.4.41
Información de contexto:
Recientemente lancé un nuevo sitio web para un cliente. Durante el proceso de rediseño decidimos:
- Cambiar a HTTPS en todo el sitio
- Eliminar la extensión .php de las URL
- Cambiar a un CMS
Ejemplo de URL ANTIGUA:
http://www.example.com/courses/acme-course.php
Ejemplo de NUEVA URL:
https://www.example.com/courses/acme-course
Mi problema:
Se produce un redireccionamiento 301 adicional innecesario cuando un usuario navega a una de las URL ANTIGUAS.
No entiendo por qué se crea el redireccionamiento 301 adicional y no envía al usuario directamente a la URL de destino correcta mediante un único redireccionamiento 301.
Observación interesante:
El redireccionamiento 301 adicional innecesario no ocurre cuando uso la URL ANTIGUA con HTTPS en lugar de HTTP.
Ejemplo:
https://www.example.com/courses/acme-course.php
_
El uso de la URL anterior realizará correctamente un único redireccionamiento 301 a la URL de destino correcta de:https://www.example.com/courses/acme-course
Aquí hay un ejemplo de una cadena de redireccionamiento 301:
URL de solicitud original:
http://www.example.com/courses/acme-course.php
1er redireccionamiento 301 (innecesario):
DE:
http://www.example.com/courses/acme-course.php
A:
https://www.example.com/index.php?url=courses/acme-course.php
2.º redireccionamiento 301 (URL de destino final correcta):
DE:
https://www.example.com/index.php?url=courses/acme-course.php
A:
https://www.example.com/courses/acme-course
Mi código .htaccess:
# (1) General Settings
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine On
</IfModule>
# (2) Force WWW
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=off
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
# (3) Force HTTPS
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
# (4) URL Routing for CMS
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} =on
RewriteRule ^ - [env=proto:https]
RewriteCond %{HTTPS} !=on
RewriteRule ^ - [env=proto:http]
## Check if file/directory exists
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
## Route all other URLs to index.php/URL
RewriteRule ^(.*)$ index.php?url=$1 [PT,L,QSA]
</IfModule>
Respuesta1
Tienes dos problemas principales....
- Sus directivas están en el orden incorrecto en el
.htaccess
archivo. Su HTTP a HTTPS ywww
sus redirecciones canónicas deben desaparecerantessu controlador frontal que enruta la URL a su CMS. De ahí la redirección externa incorrecta a/index.php?url=courses/acme-course.php
: exponer la estructura interna de URL de su CMS.
¿ La eliminación de
.php
en realidad no se realiza según sus.htaccess
directivas? Supongo que esto lo debe hacer la lógica de su aplicación/CMS. En consecuencia, esto serásiempreresultará en una segunda redirección (ya que.htaccess
se redirige a HTTPS en la misma ruta URL). Debe hacer algo como lo siguiente en la parte superior de su.htaccess
archivo para eliminar la.php
extensión.RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]
ACTUALIZAR:Si reordeno las reglas/condiciones, ¿mi ubicación de Opciones +Seguir enlaces simbólicos permanece igual?
Realmente no importadóndese produce la Options
directiva. Sin embargo, es lógico (desde el punto de vista de la legibilidad) tenerlo cerca de la parte superior. (Las directivas de Apache no necesariamente se ejecutan en el orden en que aparecen en el archivo de configuración, ya que cada módulo funciona de forma independiente).
Suponiendo que esté codificando su .htaccess
archivo a mano, entonces podrá ordenarlo...
No hay necesidad de (múltiples)
<IfModule mod_rewrite.c>
envoltorios. ¿Es mod_rewrite opcional? ¿Su sitio se trasladará a varios servidores donde mod_rewrite no está habilitado?No hay necesidad de múltiples
RewriteEngine
directivas. Elúltimoejemplo en realidadganay controla todo el archivo.Múltiples
<IfModule>
bloques yRewriteEngine
son típicos de sistemas que se editan automáticamente mediante código y/o están diseñados para funcionar sin editar en múltiples servidores.
Entonces, su .htaccess
archivo debería reescribirse así en este orden:
Options +FollowSymlinks
# Enable the rewrite engine...
RewriteEngine On
# ----------------------------------------------------------------------
# | Forcing `https://` |
# ----------------------------------------------------------------------
# Redirect to HTTPS on the "same host" (requirement for HSTS)
RewriteCond %{HTTPS} !=on
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
# ----------------------------------------------------------------------
# | Forcing `www` |
# ----------------------------------------------------------------------
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# ----------------------------------------------------------------------
# | URL Routing for CMS |
# ----------------------------------------------------------------------
# (3)
RewriteCond %{HTTPS} =on
RewriteRule ^ - [env=proto:https]
RewriteCond %{HTTPS} !=on
RewriteRule ^ - [env=proto:http]
# (4) - Check if physical file exists
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# (5) - Rewrite all other URLs to index.php/URL
RewriteRule (.*) index.php?url=$1 [L,QSA]
Notas adicionales:
La
PROTO
variable de entorno contiene cualquier protocolo que se solicite. Con el orden de las redirecciones, ahora siempre será HTTPS. El motivo de esta variable es que el CMS puede redirigir a HTTP si se accede a HTTP, o a HTTPS si se accede a HTTPS. Si está forzando HTTPS, entonces realmente no se aplica. (Aunque su aplicación aún puede utilizar esta var de entorno).Rara vez deberías usar la
NC
bandera en una condición negada. Por eso lo eliminé de la condición!^www\.
. Desea que se redirija cuando el host no comienza conwww.
todo en minúsculas. Con laNC
bandera no se podrá redirigirWwW.
, aunque esto sería muy raro de todos modos.Eliminé la verificación innecesaria de HTTPS en la redirección canónica www.
La
PT
bandera en la hormaRewriteRule
no es obligatoria en.htaccess
. Este.htaccess
es el comportamiento predeterminado (pasar).Deberá borrar el caché de su navegador antes de realizar la prueba, ya que es probable que el navegador haya almacenado en caché los redireccionamientos 301 erróneos. Por este motivo, es una buena idea realizar pruebas con redireccionamientos 302 (temporales).