.HTACCESS está creando una cadena de redireccionamiento 301 innecesaria: ¿cómo eliminarla?

Jan 12 2020

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 para 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 URL NUEVA:
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 se envía al usuario directamente a la URL de destino correcta mediante un solo redireccionamiento 301.

Observación interesante:

El redireccionamiento 301 adicional innecesario no ocurre cuando utilizo la URL ANTIGUA con HTTPS en lugar de HTTP.

Ejemplo:
https://www.example.com/courses/acme-course.php _

El uso de la URL anterior hará 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

Primer redireccionamiento 301 (innecesario):

DESDE:

http://www.example.com/courses/acme-course.php

A:

https://www.example.com/index.php?url=courses/acme-course.php

Segundo redireccionamiento 301 (URL de destino final correcta):

DESDE:

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>

Respuestas

MrWhite Jan 12 2020 at 02:19

Tienes dos problemas principales ...

  1. Sus directivas están en el orden incorrecto en el .htaccessarchivo. Su HTTP a HTTPS y las wwwredirecciones canónicas deben ir antes que su controlador frontal que enruta la URL a su CMS. De ahí el redireccionamiento externo incorrecto para /index.php?url=courses/acme-course.phpexponer la estructura interna de la URL de su CMS.
  1. ¿La eliminación de en .phprealidad no está siendo realizada por sus .htaccessdirectivas? Supongo que esto debe ser realizado por su aplicación / lógica CMS. En consecuencia, esto siempre resultará en una segunda redirección (ya que .htaccessse redirige a HTTPS en la misma ruta de URL). Debe hacer algo como lo siguiente en la parte superior de su .htaccessarchivo para eliminar la .phpextensión.

    RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]
    

ACTUALIZACIÓN: Si vuelvo a ordenar las reglas / condiciones, ¿mi ubicación de Options + FollowSymlinks permanece igual?

Realmente no importa dóndeOptions ocurra la 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 se ejecutan necesariamente 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 manualmente su .htaccessarchivo, entonces se puede ordenar ...

  1. No hay necesidad de <IfModule mod_rewrite.c>envoltorios (múltiples) . ¿Mod_rewrite es opcional? ¿Su sitio se trasladará a varios servidores donde mod_rewrite no está habilitado?

  2. No hay necesidad de varias RewriteEnginedirectivas. La última instancia gana y controla todo el archivo.

    Múltiples <IfModule>bloques y RewriteEngineson típicos de sistemas que se editan automáticamente por código y / o están diseñados para funcionar sin editar en múltiples servidores.

Entonces, su .htaccessarchivo debe 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 PROTOvariable 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 HTTPS si se accede a HTTPS. Si está forzando HTTPS, entonces realmente no se aplica. (Aunque su aplicación aún puede usar esta var env).

  • Rara vez debería usar la NCbandera en una condición negada. De ahí por qué lo eliminé de la condición !^www\.. Desea que se redirija cuando el host no comience con www.: todo en minúsculas. Con la NCbandera, no se redireccionará WwW., aunque esto sería muy raro de todos modos.

  • Eliminé la verificación innecesaria de HTTPS en el redireccionamiento canónico de www.

  • La PTbandera de la horma RewriteRuleno es obligatoria en .htaccess. En .htaccesseste es el comportamiento predeterminado (paso a través).

  • 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. Es una buena idea probar con redireccionamientos 302 (temporales) por este motivo.