9 min de leituraTutoriais

Redirecionamento 301 no .htaccess: Regras, Ordem, Strings de Consulta

Um redirecionamento 301 no .htaccess é uma linha de mod_alias. Aqui está essa linha, quando RewriteRule é a ferramenta certa em vez disso, e por que a ordem vence a posição da linha.

Marius Voß
DevRel · edge infra
Um redirecionamento 301 no htaccess mostrado como uma linha de mod_alias ao lado de uma regra de mod_rewrite, com a ordem de execução entre elas

Um redirecionamento 301 no .htaccess é uma linha:

Redirect 301 /old-page https://example.com/new-page

Salve isso no arquivo .htaccess na raiz de documentos do seu site e ele entra no ar imediatamente. O Apache lê o arquivo em cada solicitação, então não há reinício nem deploy. A diretiva vem do mod_alias, que está presente em praticamente toda instalação do Apache, e ela envia um 301 Moved Permanently com um cabeçalho Location. Esse é o trabalho todo.

Quase tudo o que dá errado com redirecionamentos do Apache acontece depois deste ponto: recorrer ao RewriteRule quando Redirect seria suficiente, misturar os dois módulos em um arquivo e obter uma ordem que ninguém esperava, ou perder a string de consulta no meio do caminho. Este post cobre as quatro regras que vale a pena memorizar, a pegadinha da ordem de execução que faz arquivos com aparência correta se comportarem mal, e como testar um redirecionamento sem que o seu navegador minta para você. Para o panorama mais amplo de onde os redirecionamentos podem viver, veja como redirecionar uma URL.

A Única Linha Que Cobre a Maioria dos Redirecionamentos

Redirect recebe um status, um caminho para corresponder, e um destino. O destino pode ser uma URL completa ou um caminho no mesmo host:

Redirect 301 /old-page /new-page
Redirect 301 /shop https://shop.example.com/
RedirectMatch 301 ^/blog/([0-9]{4})/(.*)$ /articles/$2

Dois comportamentos vale a pena conhecer antes de usá-la. Primeiro, a própria orientação do Apache é explícita ao dizer que essa é a ferramenta certa: "Esse tipo de redirecionamento simples de uma URL, ou de uma classe de URLs, para outro lugar, deve ser feito usando essas diretivas em vez de RewriteRule."

Segundo, e esse surpreende as pessoas: "Lembre-se de que Redirect preserva a informação de caminho. Ou seja, um redirecionamento para uma URL /one também vai redirecionar todas as URLs abaixo dela, como /one/two.html e /one/three/four.html." Se você quiser apenas o caminho exato, RedirectMatch 301 ^/one$ o ancora. Caso contrário, você acabou de redirecionar uma subárvore inteira, o que às vezes é exatamente o que você queria e às vezes é uma manhã muito confusa.

RedirectMatch é a versão com regex, e ela cobre a maior parte do motivo pelo qual as pessoas abrem o mod_rewrite. Os grupos capturados caem em $1, $2, e assim por diante, então renomear um diretório ou mudar um esquema de URL baseado em data se torna uma única linha.

Quando Você Realmente Precisa do RewriteRule

Recorra ao mod_rewrite quando a decisão depender de algo além do caminho. Host, string de consulta, método da solicitação, cookies, e user agent estão todos visíveis para o RewriteCond e invisíveis para o Redirect:

RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)ref=oldpartner(&|$)
RewriteRule ^landing$ /partners/oldpartner? [R=301,L]

Existe uma pegadinha no contexto por diretório que explica uma grande parte das regras copiadas e coladas que não fazem absolutamente nada. O Apache remove o prefixo do diretório antes de fazer a correspondência, então o padrão nunca vê uma barra inicial: "O prefixo removido sempre termina com uma barra, o que significa que a correspondência ocorre em uma string que nunca tem uma barra inicial. Portanto, um Pattern com ^/ nunca corresponde em contexto por diretório."

É por isso que RewriteRule ^/old$ /new [R=301] funciona quando alguém a cola em um virtual host e falha silenciosamente em .htaccess. Retire a barra: ^old$. Quando a sua substituição é um caminho relativo e a reescrita vive em um subdiretório, você também pode precisar de RewriteBase para dizer ao Apache em relação a que os caminhos são relativos.

A Pegadinha da Ordem de Execução

Essa é a que custa uma tarde inteira às pessoas. A posição da linha no arquivo não decide qual módulo é executado primeiro.

O Apache documenta isso claramente: "Se você misturar Redirect e RewriteRule no mesmo contexto, esteja ciente de que a ordem de execução deles depende de onde eles aparecem. No contexto de servidor/virtual-host, o mod_rewrite é executado primeiro; no contexto por diretório (.htaccess), o mod_alias é executado primeiro."

Leia isso duas vezes, porque a consequência é contraintuitiva. Em um arquivo .htaccess, um Redirect no final do arquivo vence um RewriteRule no topo. Mova as mesmas regras para um virtual host e o vencedor se inverte. A flag [L] também não salva você: ela significa a última regra nesta passagem do mod_rewrite, não a última regra do arquivo, e ela não tem autoridade sobre outro módulo.

A regra prática que eu sigo: um módulo por arquivo. Se um projeto precisar de condições em algum lugar, faça todos os seus redirecionamentos com mod_rewrite e apague as linhas Redirect. Arquivos misturados são de onde vêm os relatos de bug que dizem "o redirecionamento funciona no staging mas não em produção", porque os dois ambientes colocam as regras em contextos diferentes.

Ordem de execução do mod_alias e do mod_rewrite mostrando que em um arquivo htaccess o mod_alias é executado primeiro, independentemente da posição da linha

Strings de Consulta: Mantidas, Substituídas ou Apagadas

Links de marketing vivem e morrem pelas suas strings de consulta, então essa tabela vale a pena fixar na parede. Tudo isso é comportamento documentado, e não folclore.

O que você escreveString de consulta originalNotas
Redirect 301 /a /bTransportadaO mod_alias a acrescenta para você
RedirectMatch 301 ^/a$ /bTransportadaMesmo módulo, mesmo comportamento
RewriteRule ^a$ /b [R=301]Passa sem alteraçãoO padrão documentado
RewriteRule ^a$ /b?src=x [R=301]Substituída pela suaOs seus parâmetros vencem
RewriteRule ^a$ /b?src=x [R=301,QSA]Combinada com a suaO QSA acrescenta a original
RewriteRule ^a$ /b? [R=301]ApagadaUm ? isolado a limpa

A redação do Apache sobre o padrão: "Por padrão, a string de consulta passa sem alteração." E sobre as flags, [QSA] "acrescenta qualquer string de consulta da URL da solicitação original a qualquer string de consulta criada no destino da reescrita", enquanto [QSD] descarta a que está chegando. Se você redirecionar para uma URI absoluta, a string de consulta acompanha, a menos que você peça [QSD].

A falha que isso evita é silenciosa e cara. Uma regra que substitui a string de consulta remove utm_source e utm_campaign no meio do caminho, a sua ferramenta de análise atribui a sessão a tráfego direto, e nada dá erro. Ninguém percebe até alguém perguntar por que a campanha da primavera não recebeu crédito. Parâmetros UTM não aparecem no GA4 cobre o diagnóstico do lado da análise.

Se você se pegar mantendo dezenas de redirecionamentos de campanha em um arquivo de configuração do servidor, isso é um sinal, e não apenas uma tarefa chata. Regras no servidor exigem um deploy, uma revisão da configuração do Apache, e alguém com acesso shell. Mova os links de campanha para links curtos que você mesmo pode editar e mantenha o .htaccess para os redirecionamentos estruturais nos quais ele é bom.

HTTPS e www em Um Salto, Não em Dois

O trecho mais copiado da internet faz isso em dois blocos de regras, o que significa que um visitante chegando em http://example.com/page é redirecionado duas vezes: uma para adicionar TLS, outra para adicionar www. Dois saltos, duas viagens de ida e volta, e um sinal um pouco mais fraco em cada uma.

Uma regra, duas condições, um salto:

RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]

Atrás de um CDN ou de um balanceador de carga, %{HTTPS} geralmente é off na origem, mesmo quando o visitante está em HTTPS, porque o TLS terminou upstream. Teste %{HTTP:X-Forwarded-Proto} em vez disso:

RewriteCond %{HTTP:X-Forwarded-Proto} !https

Errar isso e você constrói um loop de redirecionamento infinito: o proxy envia HTTPS, a origem pensa que é HTTP, redireciona para HTTPS, e assim ele roda até o navegador desistir. Como corrigir um loop de redirecionamento percorre o diagnóstico disso a partir dos cabeçalhos de resposta.

Duas regras separadas no htaccess produzindo uma cadeia de redirecionamento de dois saltos, comparada com uma única regra que alcança a URL canônica HTTPS www em um salto

Por Que Não Está Funcionando

Na ordem em que eu verifico:

  1. AllowOverride está definido como None. A documentação do Apache descreve o padrão: "Isso significa que os arquivos .htaccess são completamente ignorados, a menos que você os habilite explicitamente para um diretório." Teste isso colocando lixo proposital na primeira linha. Nenhum erro 500 significa que o seu arquivo não está sendo lido de forma alguma, e toda regra dentro dele é decoração.
  2. O arquivo está no lugar errado ou com o nome errado. Ele precisa ser .htaccess, com o ponto inicial, no diretório para o qual a solicitação mapeia. Editores que "gentilmente" salvam como htaccess.txt são uma causa recorrente.
  3. O mod_rewrite não está carregado. Redirect funciona, RewriteRule falha silenciosamente, o que faz as pessoas ficarem examinando o próprio regex por uma hora.
  4. O seu navegador armazenou o 301 antigo em cache. Tanto o Chrome quanto o Firefox armazenam redirecionamentos permanentes de forma agressiva, por perfil de navegador, então a correção que você acabou de implantar fica invisível para você e funcionando bem para todo mundo. Durante o desenvolvimento, use R=302 e mude para R=301 quando a regra estiver correta.
  5. A regra corresponde ao seu próprio destino. RewriteRule ^(.*)$ /index.php/$1 sem uma proteção é o clássico. Adicione uma condição que isente o destino.

Teste Com curl, Não Com o Navegador

Um único comando diz o status, o destino, e quantos saltos foram necessários:

curl -sIL https://example.com/old-page | grep -iE '^HTTP|^location'

Leia a saída como uma sequência. Duas linhas HTTP/2 301 antes do 200 significam dois saltos, e cada salto é uma viagem de ida e volta real para um visitante real em uma rede móvel. A documentação do Google sobre redirecionamentos trata um redirecionamento permanente como o sinal mais forte para consolidar uma URL, e chegar lá em uma etapa é estritamente melhor do que chegar em três. Nosso verificador de links imprime a mesma cadeia em um navegador, e 301 vs 302: qual redirecionamento usar cobre qual status enviar quando você não tem certeza.

Teste os caminhos que importam, não apenas o que você acabou de escrever: a raiz, um caminho profundo, um caminho com uma string de consulta, e o próprio destino. Esse último detecta loops antes que os seus visitantes o façam.

Quando Não Usar o .htaccess de Forma Alguma

A própria posição do Apache é inequívoca. "Se você tem acesso ao arquivo de configuração principal do servidor, você deveria colocar toda a sua configuração lá em vez de em arquivos .htaccess," porque a análise a cada solicitação custa trabalho real: "permitir arquivos .htaccess causa uma perda de desempenho, quer você realmente os use ou não." Em hospedagem compartilhada você não tem escolha. Em um servidor que você controla, a configuração principal é o lugar melhor para qualquer coisa estrutural.

Existe um segundo motivo para manter as regras totalmente fora do arquivo, e não tem nada a ver com desempenho. Redirecionamentos que aparecem em material impresso, em um código QR, ou no slide de outra pessoa precisam sobreviver ao seu servidor web, à sua migração de CMS, e possivelmente ao seu provedor de hospedagem. Uma regra no .htaccess está a apenas um deploy descuidado de desaparecer, e ninguém denuncia um link impresso morto até a campanha terminar. Redirecionamentos estruturais pertencem ao servidor; links de campanha e de material impresso pertencem a algum lugar que você possa editar em segundos e medir sem vasculhar logs de acesso.

Leia a Série Principal

Este post está no cluster de tutoriais. Para o mapa completo, tipos de redirecionamentos cobre todos os códigos de status e métodos do lado do cliente, e como redirecionar uma URL cobre os seis lugares onde um redirecionamento pode viver.

Relacionados no blog

Perguntas frequentes

Como eu crio um redirecionamento 301 no .htaccess?

Coloque uma linha no arquivo .htaccess na raiz de documentos do seu site: Redirect 301 /old-page https://example.com/new-page. O Apache lê o .htaccess em cada solicitação, então o redirecionamento entra no ar no momento em que você salva o arquivo. Sem reiniciar, sem deploy. Essa diretiva vem do mod_alias, que está habilitado em praticamente toda instalação do Apache.

Qual é a diferença entre Redirect e RewriteRule?

Redirect e RedirectMatch vêm do mod_alias e fazem uma coisa: enviam um código de status e um cabeçalho Location. RewriteRule vem do mod_rewrite e pode inspecionar o host, a string de consulta, cookies, ou o user agent antes de decidir. A própria documentação do Apache diz que redirecionamentos simples devem usar mod_alias em vez de RewriteRule, e trata o mod_rewrite como último recurso.

Por que meu redirecionamento no .htaccess não está funcionando?

Cinco causas cobrem quase tudo: o AllowOverride está definido como None, então o arquivo é ignorado por completo; o arquivo não está na raiz de documentos ou tem o nome errado; o mod_rewrite não está carregado; o seu navegador armazenou em cache um 301 anterior e nunca pergunta ao servidor de novo; ou a regra corresponde ao seu próprio destino e entra em loop. Teste com curl em vez de um navegador, porque um 301 em cache faz uma regra corrigida parecer quebrada.

A string de consulta sobrevive a um redirecionamento 301 no .htaccess?

Com Redirect e RedirectMatch, sim, ela é transportada automaticamente. Com RewriteRule a resposta depende da substituição: sem ponto de interrogação nela e a string de consulta original passa direto, um ponto de interrogação com os seus próprios parâmetros a substitui, um ponto de interrogação isolado no final a apaga, e a flag QSA combina as duas. Errar isso descarta parâmetros UTM silenciosamente.

Como eu redireciono HTTP para HTTPS e non-www para www em um único salto?

Use uma regra com duas condições unidas por OR, reescrevendo para o esquema e o host canônicos em uma única etapa. Dois blocos de regras separados produzem dois redirecionamentos para quem chega em http:// sem www, e cada salto extra custa latência e dilui o sinal. Atrás de um proxy ou CDN, teste %{HTTP:X-Forwarded-Proto} em vez de %{HTTPS}, ou você vai construir um loop.

O .htaccess deixa um site mais lento?

Um pouco, e de forma inevitável. A documentação do Apache é direta sobre isso: permitir arquivos .htaccess causa uma perda de desempenho, use-os ou não, porque o httpd procura o arquivo em cada diretório em cada solicitação. Se você tem acesso à configuração principal do servidor, as mesmas regras deveriam estar lá, carregadas uma única vez na inicialização.

Experimente Elido

Cole uma URL, obtenha um link curto

Sem cadastro. O link vive 30 dias. Cadastre-se para mantê-lo para sempre.

Grátis, sem necessidade de registo · 2 por dia

Experimente o Elido

Encurtador de URL hospedado na UE: domínios personalizados, análises profundas e API aberta. Plano gratuito - sem cartão de crédito.

Tags
htaccess 301 redirect
apache redirect
mod_rewrite
301 redirect
redirect https
url redirect

Continuar lendo