Redirigir, cambiar URL o redirigir HTTP a HTTPS en Apache: todo lo que siempre quiso saber sobre las reglas mod_rewrite pero temía preguntar

Redirigir, cambiar URL o redirigir HTTP a HTTPS en Apache: todo lo que siempre quiso saber sobre las reglas mod_rewrite pero temía preguntar

Esto es unPregunta canónicasobre mod_rewrite de Apache.

Cambiar una URL de solicitud o redirigir a los usuarios a una URL diferente a la que solicitaron originalmente se realiza usando mod_rewrite. Esto incluye cosas tales como:

  • Cambiar HTTP a HTTPS (o al revés)
  • Cambiar una solicitud a una página que ya no existe a una nueva de reemplazo.
  • Modificar un formato de URL (como ?id=3433 a /id/3433 )
  • Presentar una página diferente según el navegador, según el referente, según todo lo posible bajo la luna y el sol.
  • Cualquier cosa que quieras jugar con la URL

¡Todo lo que siempre quisiste saber sobre las reglas Mod_Rewrite pero tenías miedo de preguntar!

¿Cómo puedo convertirme en un experto en escribir reglas mod_rewrite?

  • ¿Cuál es el formato y la estructura fundamentales de las reglas mod_rewrite?
  • ¿Qué forma/tipo de expresiones regulares necesito tener un conocimiento sólido?
  • ¿Cuáles son los errores/trampas más comunes al escribir reglas de reescritura?
  • ¿Cuál es un buen método para probar y verificar las reglas mod_rewrite?
  • ¿Existen implicaciones para el SEO o el rendimiento de las reglas mod_rewrite que debo tener en cuenta?
  • ¿Existen situaciones comunes en las que mod_rewrite puede parecer la herramienta adecuada para el trabajo pero no lo es?
  • ¿Cuáles son algunos ejemplos comunes?

Un lugar para poner a prueba tus reglas

Elprobador de htaccessEl sitio web es un gran lugar para jugar con sus reglas y probarlas. Incluso muestra el resultado de depuración para que puedas ver qué coincidió y qué no.

Respuesta1

orden de sintaxis mod_rewrite

mod_rewrite tiene algunas reglas de orden específicas que afectan el procesamiento. Antes de hacer algo, RewriteEngine Ones necesario dar la directiva, ya que esto activa el procesamiento mod_rewrite. Esto debería ser antes de cualquier otra directiva de reescritura.

RewriteCondanterior RewriteRulehace que UNA regla esté sujeta al condicional. Cualquier RewriteRules siguiente se procesará como si no estuviera sujeta a condicionales.

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html        $/blog/$1.sf.html

En este caso simple, si la referencia HTTP es de serverfault.com, redirija las solicitudes del blog a páginas especiales de serverfault (somos así de especiales). Sin embargo, si el bloque anterior tuviera una línea RewriteRule adicional:

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html        $/blog/$1.sf.html
RewriteRule $/blog/(.*)\.jpg         $/blog/$1.sf.jpg

Todos los archivos .jpg irían a las páginas especiales de error del servidor, no solo a los que tienen una referencia que indica que provienen de aquí. Claramente, esta no es la intención de cómo están escritas estas reglas. Se podría hacer con múltiples reglas de RewriteCond:

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html        /blog/$1.sf.html
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.jpg         /blog/$1.sf.jpg

Pero probablemente debería hacerse con alguna sintaxis de reemplazo más complicada.

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

La RewriteRule más compleja contiene los condicionales para el procesamiento. El último paréntesis (html|jpg)le dice a RewriteRule que coincida con htmlo jpgy que represente la cadena coincidente como $2 en la cadena reescrita. Esto es lógicamente idéntico al bloque anterior, con dos pares RewriteCond/RewriteRule, simplemente lo hace en dos líneas en lugar de cuatro.

A varias líneas RewriteCond se les aplica una operación AND implícitamente y se les puede aplicar una operación OR explícitamente. Para manejar referencias tanto de ServerFault como de superusuario (O explícito):

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)    [OR]
RewriteCond %{HTTP_REFERER}                ^https?://superuser\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

Para servir páginas referidas a ServerFault con navegadores Chrome (Y implícito):

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)
RewriteCond %{HTTP_USER_AGENT}             ^Mozilla.*Chrome.*$
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

RewriteBaseTambién es específico del orden, ya que especifica cómo las siguientes RewriteRuledirectivas manejan su procesamiento. Es muy útil en archivos .htaccess. Si se usa, debería ser la primera directiva en "RewriteEngine on" en un archivo .htaccess. Tome este ejemplo:

RewriteEngine On
RewriteBase /blog
RewriteCond %{HTTP_REFERER}           ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg)         $1.sf.$2

Esto le dice a mod_rewrite que esta URL en particular que está manejando actualmente llegó a través dehttp://ejemplo.com/blog/en lugar de la ruta del directorio físico (/home/$Username/public_html/blog) y tratarlo en consecuencia. Debido a esto, RewriteRuleconsidera que el inicio de la cadena está después de "/blog" en la URL. Aquí está lo mismo escrito de dos maneras diferentes. Uno con RewriteBase, el otro sin:

RewriteEngine On

##Example 1: No RewriteBase##
RewriteCond %{HTTP_REFERER}                                   ^https?://serverfault\.com(/|$)
RewriteRule /home/assdr/public_html/blog/(.*)\.(html|jpg)     $1.sf.$2

##Example 2: With RewriteBase##
RewriteBase /blog
RewriteCond %{HTTP_REFERER}           ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg)         $1.sf.$2

Como puede ver, RewriteBasepermite reescribir reglas para aprovechar la web.sitioruta al contenido en lugar de la web.servidor, lo que puede hacerlos más inteligibles para quienes editan dichos archivos. Además, pueden acortar las directivas, lo que tiene un atractivo estético.


Sintaxis de coincidencia de RewriteRule

El propio RewriteRule tiene una sintaxis compleja para hacer coincidir cadenas. Cubriré las banderas (cosas como [PT]) en otra sección. Debido a que los administradores de sistemas aprenden con el ejemplo más a menudo que leyendo unpágina de manualDaré ejemplos y explicaré lo que hacen.

RewriteRule ^/blog/(.*)$    /newblog/$1

La .*construcción coincide con cualquier carácter ( .) cero o más veces ( *). Encerrarlo entre paréntesis le indica que proporcione la cadena que coincidió como la variable $1.

RewriteRule ^/blog/.*/(.*)$  /newblog/$1

En este caso, el primer .* NO estaba entre paréntesis, por lo que no se proporciona a la cadena reescrita. Esta regla elimina un nivel de directorio en el nuevo sitio de blog. (/blog/2009/sample.html se convierte en /newblog/sample.html).

RewriteRule ^/blog/(2008|2009)/(.*)$   /newblog/$2

En este caso, la primera expresión entre paréntesis configura un grupo coincidente. Esto se convierte en $1, que no es necesario y, por lo tanto, no se utiliza en la cadena reescrita.

RewriteRule ^/blog/(2008|2009)/(.*)$   /newblog/$1/$2

En este caso, usamos $1 en la cadena reescrita.

RewriteRule ^/blog/(20[0-9][0-9])/(.*)$   /newblog/$1/$2

Esta regla utiliza una sintaxis de corchetes especial que especifica un carácter.rango. [0-9] coincide con los números del 0 al 9. Esta regla específica manejará los años del 2000 al 2099.

RewriteRule ^/blog/(20[0-9]{2})/(.*)$  /newblog/$1/$2

Esto hace lo mismo que la regla anterior, pero la parte {2} le indica que coincida con el carácter anterior (una expresión entre corchetes en este caso) dos veces.

RewriteRule ^/blog/([0-9]{4})/([a-z]*)\.html   /newblog/$1/$2.shtml

Este caso coincidirá con cualquier letra minúscula en la segunda expresión coincidente y lo hará con tantos caracteres como sea posible. La \.construcción le indica que trate el período como un período real, no como el carácter especial que tiene en los ejemplos anteriores. Sin embargo, se romperá si el nombre del archivo tiene guiones.

RewriteRule ^/blog/([0-9]{4})/([-a-z]*)\.html  /newblog/$1/$2.shtml

Esto atrapa nombres de archivos con guiones. Sin embargo, como -es un carácter especial en las expresiones entre corchetes, tiene que ser elprimerocarácter en la expresión.

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html   /newblog/$1/$2.shtml

Esta versión atrapa cualquier nombre de archivo con letras, números o -caracteres en el nombre del archivo. Así es como se especifican varios juegos de caracteres en una expresión entre corchetes.


Banderas de reescritura de reglas

Las banderas en las reglas de reescritura tienen una serie de significados y casos de uso especiales..

RewriteRule ^/blog/([0-9]{4})/([-a-z]*).\html  /newblog/$1/$2.shtml  [L]

La bandera está [L]al final de la expresión anterior. Se pueden utilizar varios indicadores, separados por una coma. La documentación vinculada describe cada uno, pero aquí están de todos modos:

l= Último. Deje de procesar RewriteRules una vez que éste coincida. ¡El pedido cuenta!
C= Cadena. Continúe procesando la siguiente RewriteRule. Si esta regla no coincide, no se ejecutará la siguiente regla. Más sobre esto más adelante.
mi= Establecer variable ambiental. Apache tiene varias variables ambientales que pueden afectar el comportamiento del servidor web.
F= Prohibido. Devuelve un error 403-Prohibido si esta regla coincide.
GRAMO= Ido. Devuelve un error 410-Gone si esta regla coincide.
h= Manejador. Fuerza que la solicitud se maneje como si fuera el tipo MIME especificado.
norte= Siguiente. Obliga a que la regla comience de nuevo y vuelva a coincidir. ¡TEN CUIDADO! Pueden producirse bucles.
CAROLINA DEL NORTE= Ningún caso. Permite jpghacer coincidir tanto jpg como JPG.
nordeste= No hay escapatoria. Evita la reescritura de caracteres especiales (. ? # & etc) en sus equivalentes en código hexadecimal.
NS= Sin subsolicitudes. Si está utilizando inclusiones del lado del servidor, esto evitará coincidencias con los archivos incluidos.
PAG= Apoderado. Fuerza que la regla sea manejada por mod_proxy. Proporcione contenido de forma transparente desde otros servidores, porque su servidor web lo recupera y lo vuelve a servir. Esta es una señal peligrosa, ya que una mal escrita convertirá su servidor web en un proxy abierto y eso es malo.
PT= Pasar. Tenga en cuenta las declaraciones de alias en la coincidencia de RewriteRule.
QSA= QSAgregar. Cuando la cadena original contiene una consulta (http://ejemplo.com/cosa?asp=foo) agrega la cadena de consulta original a la cadena reescrita. Normalmente sería descartado. Importante para contenido dinámico.
R= Redirigir. Proporcione una redirección HTTP a la URL especificada. También puede proporcionar un código de redireccionamiento exacto [R=303]. Muy similar a RedirectMatch, que es más rápido y debe usarse cuando sea posible.
S= Saltar. Salta esta regla.
t= Tipo. Especifique el tipo MIME del contenido devuelto. Muy similar a la AddTypedirectiva.

¿Sabes que dije que eso RewriteCondse aplica a una y sólo una regla? Bueno, puedes solucionar eso encadenando.

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html        /blog/$1.sf.html     [C]
RewriteRule ^/blog/(.*)\.jpg         /blog/$1.sf.jpg

Debido a que la primera RewriteRule tiene el indicador Cadena, la segunda regla de reescritura se ejecutará cuando la primera lo haga, que es cuando la regla RewriteCond anterior coincide. Útil si las expresiones regulares de Apache le duelen el cerebro. Sin embargo, el método todo en uno que señalé en la primera sección es más rápido desde el punto de vista de la optimización.

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html   /newblog/$1/$2.shtml

Esto se puede simplificar mediante banderas:

RewriteRule ^/blog/([0-9]{4})/([-0-9a-z]*)\.html   /newblog/$1/$2.shtml   [NC]

Además, algunas marcas también se aplican a RewriteCond. En particular, NoCase.

RewriteCond %{HTTP_REFERER}        ^https?://serverfault\.com(/|$)     [NC]

Coincidirá con "ServerFault.com"

Respuesta2

¿Cuál es el formato y la estructura fundamentales de las reglas mod_rewrite?

Me remitiré a la excelente respuesta de sysadmin1138 sobre estos puntos.

¿Qué forma/tipo de expresiones regulares necesito tener un conocimiento sólido?

Además del orden de sintaxis, la coincidencia de sintaxis/expresiones regulares y los indicadores RewriteRule descritos por sysadmin1138, creo que vale la pena mencionar que mod_rewrite expone variables de entorno de Apache basadas en encabezados de solicitud HTTP y la configuración de Apache.

yo recomendariaTutorial de depuración mod_rewrite de AskApachepara obtener una lista completa de variables que pueden estar disponibles para mod_rewrite.

¿Cuáles son los errores/trampas más comunes al escribir reglas de reescritura?

La mayoría de los problemas con RewriteRule se deben a una mala comprensión de la sintaxis de PCRE, a una falla al escapar correctamente de los caracteres especiales o a una falta de conocimiento del contenido de las variables utilizadas para la comparación.

Problemas típicos y solución de problemas recomendada:

  • Error interno de servidor 500-Quitar los controles del carro de Windowsen los archivos de configuración, si están presentes, asegúrese de que mod_rewrite esté habilitado (envuelva las directivas enIfModulecondicional para evitar este escenario), verifique la sintaxis de la directiva, comente las directivas hasta que se identifique el problema
  • Bucle de redireccionamiento- Utilice RewriteLog y RewriteLogLevel, comente las directivas hasta que se identifique el problema.

¿Cuál es un buen método para probar y verificar las reglas mod_rewrite?

Primero, observe el contenido de las variables de entorno con las que planea comparar; si tiene PHP instalado, esto es tan simple como agregar el siguiente bloque a su aplicación:

<?php
  var_dump($_SERVER);
?>

... luego escriba sus reglas (preferiblemente para probar en un servidor de desarrollo) y anote cualquier coincidencia o actividad inconsistente en su ApacheRegistro de erroresarchivo.

Para reglas más complejas, use mod_rewriteRewriteLogdirectiva para registrar la actividad en un archivo y establecerRewriteLogLevel 3

¿Existen implicaciones para el SEO o el rendimiento de las reglas mod_rewrite que debo tener en cuenta?

AllowOverride allafecta el rendimiento del servidor ya que Apache debe buscar .htaccessarchivos y analizar directivas con cada solicitud; si es posible, mantenga todas las directivas en la configuración de VirtualHost para su sitio o habilite .htaccesslas anulaciones solo para los directorios que las necesitan.

de googleDirectrices para webmastersIndique explícitamente: "No engañe a sus usuarios ni presente a los motores de búsqueda contenido diferente al que muestra a los usuarios, lo que comúnmente se conoce como 'encubrimiento'". Evite crear directivas mod_rewrite que filtren los robots de los motores de búsqueda.

Los robots de los motores de búsqueda prefieren un contenido 1:1: mapeo de URI (esta es la base para clasificar los enlaces al contenido). Si está utilizando mod_rewrite para crear redireccionamientos temporales o está ofreciendo el mismo contenido bajo múltiples URI, considere especificar unURI canónicadentro de sus documentos HTML.

¿Existen situaciones comunes en las que mod_rewrite puede parecer la herramienta adecuada para el trabajo pero no lo es?

Este es un tema enorme (y potencialmente polémico) en sí mismo: es mejor (en mi humilde opinión) abordar los usos caso por caso y dejar que quienes preguntan determinen si las resoluciones sugeridas son apropiadas para sus necesidades.

¿Cuáles son algunos ejemplos comunes?

Trucos y consejos mod_rewrite de AskApachecubre casi todos los casos de uso comunes que aparecen regularmente; sin embargo, la solución "correcta" para un usuario determinado puede depender de la sofisticación de la configuración del usuario y de las directivas existentes (razón por la cual generalmente es una buena idea ver quéotrodirectivas que un usuario tiene implementadas cada vez que surge una pregunta mod_rewrite).

Respuesta3

Como muchos administradores/desarrolladores, he estado luchando contra las complejidades de las reglas de reescritura durante años y no estoy satisfecho con la documentación existente de Apache, por lo que decidí, como proyecto personal, llegar al fondo de cómo mod_rewritefunciona e interactúa realmente con el resto de Apache. core, por lo que durante los últimos meses he estado instrumentando casos de prueba con strace+ profundización en el código fuente para controlar todo esto.

Aquí hay algunos comentarios clave que los desarrolladores de reglas de reescritura deben considerar:

  • Algunos aspectos de la reescritura son comunes a la configuración del servidor, el host virtual, el directorio y el procesamiento de .htaccess.sin embargo
  • Algunos procesos son muy diferentes para la configuración raíz (configuración del servidor, host virtual y directorio) en comparación con el .htaccessprocesamiento PerDir ().
  • Peor aún, debido a que el procesamiento PerDir puede desencadenar casi indiscriminadamente el ciclo de REDIRECCIÓN INTERNA, los elementos de configuración raíz deben escribirse teniendo en cuenta que dicho procesamiento PerDir puede desencadenar esto.

Me atrevería a decir que debido a esto casi es necesario dividir las comunidades de usuarios de reescritura en dos categorías y tratarlas como completamente separadas:

  • Aquellos con acceso root a la configuración de Apache. Por lo general, son administradores/desarrolladores con un servidor/VM dedicado a la aplicación, y el mensaje aquí es bastante simple: evite el uso de .htaccessarchivos si es posible; haga todo en su servidor o configuración de vhost. La depuración es razonablemente sencilla ya que el desarrollador puede configurar la depuración y tiene acceso a los archivos rewrite.log.

  • Usuarios de un servicio alojado compartido (SHS).

    • Tales usuariostenerutilizar .htaccessel procesamiento / Perdir ya que no hay ninguna alternativa disponible.
    • Peor aún, el nivel de habilidad de dichos usuarios (en lo que respecta al uso de la lógica de escalera basada en expresiones regulares de mod_rewrite) es generalmente significativamente menor que el de los administradores experimentados.
    • Apache y los proveedores de hosting no ofrecen soporte de depuración/diagnóstico. La única información de diagnóstico es una redirección exitosa, una redirección al URI incorrecto. o un código de estado 404/500. Esto los deja confundidos e indefensos.
    • Apache es extremadamente débil al explicar cómo funciona la reescritura para este caso de uso. Por ejemplo, no proporciona una explicación clara de qué .htaccessarchivo PerDir se selecciona y por qué. No explica las complejidades del ciclo PerDir y cómo evitarlo.

Posiblemente exista una tercera comunidad: el personal administrativo y de apoyo de los proveedores de SHS que terminan con un pie en ambos campos y tienen que sufrir las consecuencias de lo anterior.

He escrito un par de publicaciones de blog estilo artículo (p. ej.Más información sobre el uso de reglas de reescritura en archivos .htaccess) que cubre muchos puntos detallados que no repetiré aquí para que esta publicación sea breve. Tengo mi propio servicio compartido y también admito algunos proyectos dedicados y VM FLOSS. Comencé usando una VM LAMP estándar como vehículo de prueba para mi cuenta SHS, pero al final encontré que era mejor hacer una VM espejo adecuada (descritaaquí).

Sin embargo, en términos de cómo la comunidad de administradores debería apoyar .htaccessa los usuarios, creo que necesitamos desarrollar y ofrecer:

  • Una descripción coherente de cómo funciona realmente el sistema de reescritura en el procesamiento PerDir
  • Un conjunto de pautas/mejores prácticas sobre cómo escribir .htaccessreglas de reescritura
  • Un sencillo analizador de secuencias de comandos de reescritura basado en web similar a los analizadores HTML del W3C, pero mediante el cual los usuarios pueden ingresar URI de prueba o vectores de prueba de los mismos y obtener un registro inmediato del flujo lógico de reescritura.
  • Consejos sobre cómo obtener diagnósticos integrados de sus reglas (p. ej.

    • Utilice [E=VAR:EXPR]el hecho de aprovechar el hecho de que EXPRexpandirá las referencias anteriores ($N o %N) para que estén disponibles como diagnóstico para el script de destino.
    • Si ordena tópicamente sus reglas de reescritura usando los indicadores [OR],[C],[SKIP] y [L] para que todo el esquema de reescritura funcionesinla necesidad de explotar la redirección interna, entonces puedes agregar lo siguiente como regla 1 para evitar todos los problemas de bucles:

      RewriteCond %{ENV:REDIRECT_STATUS} !=""
      RewriteRule .  -  [L]
      

Respuesta4

¿Cuáles son los errores/trampas más comunes al escribir reglas de reescritura?

Un error realmente fácil es reescribir URL que alteran la ruta aparente, por ejemplo, de /base/1234/index.htmla /base/script.php?id=1234. El cliente no encontrará ninguna imagen o CSS con rutas relativas a la ubicación del script. Se pueden encontrar varias opciones para resolver esto enestas preguntas frecuentes.

información relacionada