Redirecionar, alterar URLs ou redirecionar HTTP para HTTPS no Apache – tudo o que você sempre quis saber sobre as regras do mod_rewrite, mas tinha medo de perguntar

Redirecionar, alterar URLs ou redirecionar HTTP para HTTPS no Apache – tudo o que você sempre quis saber sobre as regras do mod_rewrite, mas tinha medo de perguntar

Isto é umPergunta Canônicasobre o mod_rewrite do Apache.

A alteração de um URL de solicitação ou o redirecionamento dos usuários para um URL diferente daquele solicitado originalmente é feito usando mod_rewrite. Isso inclui coisas como:

  • Alterando HTTP para HTTPS (ou vice-versa)
  • Alterar uma solicitação para uma página que não existe mais para uma nova substituição.
  • Modificando um formato de URL (como ?id=3433 para /id/3433 )
  • Apresentar uma página diferente baseada no navegador, baseada no referenciador, baseada em tudo o que é possível sob a lua e o sol.
  • Qualquer coisa que você queira mexer com URL

Tudo o que você sempre quis saber sobre as regras do Mod_Rewrite, mas tinha medo de perguntar!

Como posso me tornar um especialista em escrever regras mod_rewrite?

  • Qual é o formato e estrutura fundamentais das regras mod_rewrite?
  • De que forma/sabor de expressões regulares eu preciso ter um conhecimento sólido?
  • Quais são os erros/armadilhas mais comuns ao escrever regras de reescrita?
  • Qual é um bom método para testar e verificar as regras do mod_rewrite?
  • Há implicações de SEO ou de desempenho das regras mod_rewrite das quais devo estar ciente?
  • Existem situações comuns em que o mod_rewrite pode parecer a ferramenta certa para o trabalho, mas não é?
  • Quais são alguns exemplos comuns?

Um lugar para testar suas regras

Otestador de htaccessO site é um ótimo lugar para brincar com suas regras e testá-las. Ele ainda mostra a saída de depuração para que você possa ver o que corresponde e o que não corresponde.

Responder1

ordem de sintaxe mod_rewrite

mod_rewrite possui algumas regras de ordenação específicas que afetam o processamento. Antes de qualquer coisa ser feita, a RewriteEngine Ondiretiva precisa ser fornecida, pois ativa o processamento mod_rewrite. Isso deve ser feito antes de qualquer outra diretiva de reescrita.

RewriteCondo anterior RewriteRuletorna aquela ÚNICA regra sujeita à condicional. Quaisquer RewriteRules seguintes serão processadas como se não estivessem sujeitas a condicionais.

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

Neste caso simples, se o referenciador HTTP for de serverfault.com, redirecione as solicitações do blog para páginas especiais de serverfault (somos tão especiais assim). No entanto, se o bloco acima tivesse uma linha RewriteRule extra:

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

Todos os arquivos .jpg iriam para as páginas especiais de serverfault, não apenas aquelas com um referenciador indicando que veio daqui. Esta claramente não é a intenção de como essas regras são escritas. Isso poderia ser feito com várias regras 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

Mas provavelmente deveria ser feito com alguma sintaxe de substituição mais complicada.

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

O RewriteRule mais complexo contém as condicionais para processamento. O último parêntese (html|jpg)diz ao RewriteRule para corresponder a htmlor jpge representar a string correspondente como $2 na string reescrita. Isso é logicamente idêntico ao bloco anterior, com dois pares RewriteCond/RewriteRule, apenas faz isso em duas linhas em vez de quatro.

Várias linhas RewriteCond são implicitamente AND e podem ser explicitamente OR. Para lidar com referenciadores de ServerFault e Superusuário (OR 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 veicular páginas referidas pelo ServerFault com navegadores Chrome (E implícito):

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

RewriteBasetambém é específico do pedido, pois especifica como RewriteRuleas diretivas a seguir tratam de seu processamento. É muito útil em arquivos .htaccess. Se usada, deverá ser a primeira diretiva em "RewriteEngine on" em um arquivo .htaccess. Veja este exemplo:

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

Isso está dizendo ao mod_rewrite que este URL específico que ele está manipulando no momento chegou por meio dehttp://example.com/blog/em vez do caminho do diretório físico (/home/$Username/public_html/blog) e tratá-lo adequadamente. Por causa disso, RewriteRuleconsidera que o início da string ocorre após "/blog" na URL. Aqui está a mesma coisa escrita de duas maneiras diferentes. Um com RewriteBase, o outro sem:

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 você pode ver, RewriteBasepermite reescrever regras para aproveitar o web-sitecaminho para o conteúdo em vez da web-servidor, o que pode torná-los mais inteligíveis para quem edita tais arquivos. Além disso, podem tornar as diretivas mais curtas, o que tem um apelo estético.


Sintaxe de correspondência RewriteRule

O próprio RewriteRule possui uma sintaxe complexa para correspondência de strings. Abordarei as bandeiras (coisas como [PT]) em outra seção. Porque os administradores de sistemas aprendem com mais frequência pelo exemplo do que lendo umpágina de manualVou dar exemplos e explicar o que eles fazem.

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

A .*construção corresponde a qualquer caractere único ( .) zero ou mais vezes ( *). Colocá-lo entre parênteses indica que ele deve fornecer a string que foi correspondida como a variável $1.

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

Nesse caso, o primeiro .* NÃO foi colocado entre parênteses, portanto não é fornecido à string reescrita. Esta regra remove um nível de diretório no novo blog. (/blog/2009/sample.html torna-se /newblog/sample.html).

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

Nesse caso, a primeira expressão entre parênteses configura um grupo correspondente. Isso se torna $1, que não é necessário e, portanto, não é usado na string reescrita.

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

Neste caso, usamos $1 na string reescrita.

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

Esta regra usa uma sintaxe especial de colchetes que especifica um caracterefaixa. [0-9] corresponde aos números de 0 a 9. Esta regra específica tratará dos anos de 2000 a 2099.

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

Isso faz a mesma coisa que a regra anterior, mas a parte {2} diz para ela corresponder ao caractere anterior (uma expressão de colchetes neste caso) duas vezes.

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

Este caso corresponderá a qualquer letra minúscula na segunda expressão correspondente e fará isso para tantos caracteres quanto possível. A \.construção diz para tratar o período como um período real, não como o caractere especial dos exemplos anteriores. Ele irá quebrar se o nome do arquivo contiver traços.

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

Isso captura nomes de arquivos com traços. No entanto, como -é um caractere especial nas expressões entre colchetes, deve ser oprimeiropersonagem na expressão.

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

Esta versão intercepta qualquer nome de arquivo com letras, números ou -caracteres no nome do arquivo. É assim que você especifica vários conjuntos de caracteres em uma expressão entre colchetes.


Sinalizadores RewriteRule

Os sinalizadores nas regras de reescrita têm vários significados e casos de uso especiais.

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

A bandeira está [L]no final da expressão acima. Vários sinalizadores podem ser usados, separados por vírgula. A documentação vinculada descreve cada um deles, mas aqui estão eles:

eu= Último. Pare de processar RewriteRules quando este corresponder. O pedido conta!
C= Corrente. Continue processando o próximo RewriteRule. Se esta regra não corresponder, a próxima regra não será executada. Mais sobre isso mais tarde.
E= Definir variável ambiental. O Apache possui várias variáveis ​​ambientais que podem afetar o comportamento do servidor web.
F= Proibido. Retorna um erro 403-Forbidden se esta regra corresponder.
G= Foi. Retorna um erro 410-Gone se esta regra corresponder.
H= Manipulador. Força a solicitação a ser tratada como se fosse do tipo MIME especificado.
N= Próximo. Força a regra a recomeçar e refazer a partida. TOME CUIDADO! Podem ocorrer loops.
NC= Nenhum caso. Permite jpgcombinar JPG e JPG.
NE= Não há escapatória. Impede a reescrita de caracteres especiais (. ? # & etc) em seus equivalentes em código hexadecimal.
E= Sem subsolicitações. Se você estiver usando inclusões no lado do servidor, isso impedirá correspondências com os arquivos incluídos.
P= Procurador. Força a regra a ser tratada pelo mod_proxy. Forneça conteúdo de outros servidores de forma transparente, porque seu servidor web o busca e o serve novamente. Este é um sinalizador perigoso, pois um sinalizador mal escrito transformará seu servidor web em um proxy aberto e isso é ruim.
PT= Passagem. Leve em consideração as instruções Alias ​​na correspondência RewriteRule.
CQS= QSAnexar. Quando a string original contém uma consulta (http://example.com/thing?asp=foo) anexa a string de consulta original à string reescrita. Normalmente seria descartado. Importante para conteúdo dinâmico.
R= Redirecionar. Forneça um redirecionamento HTTP para o URL especificado. Também pode fornecer o código de redirecionamento exato [R=303]. Muito semelhante ao RedirectMatch, que é mais rápido e deve ser usado sempre que possível.
S= Pular. Pule esta regra.
T= Tipo. Especifique o tipo mime do conteúdo retornado. Muito semelhante à AddTypedirectiva.

Você sabe como eu disse que isso RewriteCondse aplica a uma e apenas uma regra? Bem, você pode contornar isso encadeando.

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

Como o primeiro RewriteRule possui o sinalizador Chain, a segunda regra de reescrita será executada quando a primeira o fizer, que é quando a regra RewriteCond anterior for correspondida. Útil se as expressões regulares do Apache fizerem seu cérebro doer. No entanto, o método tudo-em-uma linha que aponto na primeira seção é mais rápido do ponto de vista da otimização.

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

Isso pode ser simplificado por meio de sinalizadores:

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

Além disso, alguns sinalizadores também se aplicam ao RewriteCond. Notavelmente, NoCase.

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

Corresponderá a "ServerFault.com"

Responder2

Qual é o formato e estrutura fundamentais das regras mod_rewrite?

Adiarei a excelente resposta do sysadmin1138 sobre esses pontos.

De que forma/sabor de expressões regulares eu preciso ter um conhecimento sólido?

Além da ordem de sintaxe, correspondência de sintaxe/expressões regulares e sinalizadores RewriteRule descritos por sysadmin1138, acredito que vale a pena mencionar que mod_rewrite expõe variáveis ​​de ambiente Apache com base em cabeçalhos de solicitação HTTP e na configuração do Apache.

eu recomendariaTutorial de depuração mod_rewrite do AskApachepara uma lista abrangente de variáveis ​​que podem estar disponíveis para mod_rewrite.

Quais são os erros/armadilhas mais comuns ao escrever regras de reescrita?

A maioria dos problemas com RewriteRule decorrem de um mal-entendido da sintaxe PCRE/falha em escapar adequadamente de caracteres especiais ou de uma falta de conhecimento do conteúdo das variáveis ​​usadas para correspondência.

Problemas típicos e solução de problemas recomendada:

  • 500 - Erro interno do servidor-Remover controles de carro do Windowsno(s) arquivo(s) de configuração, se presente, certifique-se de que mod_rewrite esteja habilitado (envolva as diretivas emIfModulecondicional para evitar este cenário), verifique a sintaxe da diretiva, comente as diretivas até que o problema seja identificado
  • Loop de redirecionamento- Faça uso de RewriteLog e RewriteLogLevel, comente as diretivas até que o problema seja identificado

Qual é um bom método para testar e verificar as regras do mod_rewrite?

Primeiro, observe o conteúdo das variáveis ​​de ambiente que você planeja comparar - se você tiver o PHP instalado, isso é tão simples quanto adicionar o seguinte bloco ao seu aplicativo:

<?php
  var_dump($_SERVER);
?>

... então escreva suas regras (de preferência para testes em um servidor de desenvolvimento) e anote qualquer correspondência ou atividade inconsistente em seu ApacheLog de errosarquivo.

Para regras mais complexas, use mod_rewrite'sRewriteLogdiretiva para registrar atividades em um arquivo e definirRewriteLogLevel 3

Há implicações de SEO ou de desempenho das regras mod_rewrite das quais devo estar ciente?

AllowOverride allafeta o desempenho do servidor, pois o Apache deve verificar .htaccessarquivos e analisar diretivas com cada solicitação - se possível, mantenha todas as diretivas na configuração do VirtualHost para o seu site ou habilite .htaccesssubstituições apenas para os diretórios que precisam delas.

do GoogleDiretrizes para webmastersdeclare explicitamente: "Não engane seus usuários nem apresente aos mecanismos de pesquisa conteúdo diferente do que você exibe aos usuários, o que é comumente referido como 'cloaking'." - evite criar diretivas mod_rewrite que filtram robôs de mecanismos de pesquisa.

Os robôs dos mecanismos de pesquisa preferem um mapeamento content:URI 1:1 (esta é a base para classificar links para conteúdo) - se você estiver usando mod_rewrite para criar redirecionamentos temporários ou estiver servindo o mesmo conteúdo sob vários URIs, considere especificar umURI canônicodentro de seus documentos HTML.

Existem situações comuns em que o mod_rewrite pode parecer a ferramenta certa para o trabalho, mas não é?

Este é um tópico enorme (e potencialmente controverso) por si só - melhor (IMHO) abordar os usos caso a caso e permitir que os solicitantes determinem se as resoluções sugeridas são apropriadas às suas necessidades.

Quais são alguns exemplos comuns?

Truques e dicas do mod_rewrite do AskApachecobre quase todos os casos de uso comuns que aparecem regularmente, no entanto, a solução "correta" para um determinado usuário pode depender da sofisticação da configuração do usuário e das diretivas existentes (é por isso que geralmente é uma boa ideia ver quaisoutrodiretivas que um usuário possui sempre que surge uma pergunta sobre mod_rewrite).

Responder3

Como muitos administradores/desenvolvedores, tenho lutado contra as complexidades das regras de reescrita há anos e estou insatisfeito com a documentação existente do Apache, então decidi como um projeto pessoal chegar ao fundo de como mod_rewriterealmente funciona e interage com o resto do Apache. núcleo, então, nos últimos meses, tenho instrumentado casos de teste strace+ detalhando o código-fonte para entender tudo isso.

Aqui estão alguns comentários importantes que os desenvolvedores de regras de reescrita precisam considerar:

  • Alguns aspectos da reescrita são comuns à configuração do servidor, host virtual, diretório, processamento .htaccessno entanto
  • Algum processamento é muito diferente para a configuração raiz (configuração do servidor, host virtual e diretório) em oposição ao .htaccessprocessamento PerDir ( ).
  • Pior ainda, porque o processamento PerDir pode acionar o ciclo de REDIRECT INTERNO quase indiscriminadamente, os elementos de configuração raiz devem estar cientes de que tal processamento PerDir pode acionar isso.

Eu diria que, por causa disso, você quase precisa dividir as comunidades de usuários reescritas em duas categorias e tratá-las como totalmente separadas:

  • Aqueles com acesso root à configuração do Apache. Normalmente, eles são administradores/desenvolvedores com um servidor/VM dedicado ao aplicativo, e a mensagem aqui é bastante simples: evite usar .htaccessarquivos, se possível; faça tudo na configuração do seu servidor ou vhost. A depuração é razoavelmente fácil, pois o desenvolvedor pode definir a depuração e ter acesso aos arquivos rewrite.log.

  • Usuários de um serviço hospedado compartilhado (SHS).

    • Esses usuáriosterusar .htaccess/ Perdir processamento, pois não há alternativa disponível.
    • Pior ainda, o nível de habilidade de tais usuários (no que diz respeito ao uso da lógica ladder orientada por regexp do mod_rewrite) é geralmente significativamente menor do que o de administradores experientes.
    • O Apache e os provedores de hospedagem não oferecem suporte para depuração/diagnóstico. A única informação de diagnóstico é um redirecionamento bem-sucedido, um redirecionamento para o URI errado. ou um código de status 404/500. Isso os deixa confusos e desamparados.
    • O Apache é extremamente fraco ao explicar como a reescrita funciona para este caso de uso. Por exemplo, ele não fornece uma explicação clara sobre qual .htaccessarquivo PerDir está selecionado e por quê. Não explica os meandros do ciclo PerDir e como evitá-lo.

Existe possivelmente uma terceira comunidade: pessoal administrativo e de apoio nos prestadores de SHS que acabam com um pé em ambos os campos e têm de sofrer as consequências do que precede.

Escrevi algumas postagens de blog em estilo de artigo (por exemploMais sobre como usar regras de reescrita em arquivos .htaccess) que cobre muitos pontos detalhados que não vou repetir aqui para manter este post curto. Tenho meu próprio serviço compartilhado, além de oferecer suporte a alguns projetos dedicados e VM FLOSS. Comecei usando uma VM LAMP padrão como veículo de teste para minha conta SHS, mas no final achei melhor fazer uma VM espelhada adequada (descritaaqui).

No entanto, em termos de como a comunidade administrativa deve apoiar .htaccessos utilizadores, sinto que precisamos de desenvolver e oferecer:

  • Uma descrição coerente de como o sistema de reescrita realmente funciona no processamento PerDir
  • Um conjunto de diretrizes/melhores práticas sobre como escrever .htaccessregras de reescrita
  • Um analisador de script de reescrita simples baseado na Web, semelhante aos analisadores html do W3C, mas pelo qual os usuários podem inserir URIs de teste ou vetores de teste dos mesmos e obter um log imediato do fluxo lógico de reescrita/
  • Dicas sobre como obter diagnósticos integrados de suas regras (por exemplo

    • Use [E=VAR:EXPR]a exploração do fato que EXPRexpandirá as referências anteriores ($N ou %N) para torná-las disponíveis como diagnóstico para o script de destino.
    • Se você ordenar topicamente suas regras de reescrita usando os sinalizadores [OR], [C], [SKIP] e [L] para que todo o esquema de reescrita funcionesema necessidade de explorar o redirecionamento interno, então você pode adicionar o seguinte como regra 1 para evitar todos os problemas de loop:

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

Responder4

Quais são os erros/armadilhas mais comuns ao escrever regras de reescrita?

Uma armadilha realmente fácil é quando você reescreve URLs que alteram o caminho aparente, por exemplo, de /base/1234/index.htmlpara /base/script.php?id=1234. Quaisquer imagens ou CSS com caminhos relativos ao local do script não serão encontrados pelo cliente. Várias opções para resolver isso podem ser encontradas emesta pergunta frequente.

informação relacionada