
Minha pilha:
- LÂMPADA
- Apache/2.4.41
Informações básicas:
Recentemente lancei um novo site para um cliente. Durante o processo de redesenho, decidimos:
- Mudar para HTTPS em todo o site
- Remova a extensão .php dos URLs
- Mudar para um CMS
Exemplo de URL ANTIGO:
http://www.example.com/courses/acme-course.php
Exemplo de NOVO URL:
https://www.example.com/courses/acme-course
Meu problema:
Um redirecionamento 301 adicional desnecessário está ocorrendo quando um usuário navega para um dos URLs ANTIGOS.
Não entendo por que o redirecionamento 301 adicional está sendo criado e não envia o usuário diretamente para o URL de destino correto usando um único redirecionamento 301.
Observação interessante:
O redirecionamento 301 adicional desnecessário não ocorre quando uso o URL ANTIGO com HTTPS em vez de HTTP.
Exemplo:
https://www.example.com/courses/acme-course.php
_
Usar o URL acima fará corretamente um único redirecionamento 301 para o URL de destino correto de:https://www.example.com/courses/acme-course
Aqui está um exemplo de cadeia de redirecionamento 301:
URL de solicitação original:
http://www.example.com/courses/acme-course.php
1º Redirecionamento 301 (desnecessário):
DE:
http://www.example.com/courses/acme-course.php
PARA:
https://www.example.com/index.php?url=courses/acme-course.php
2º Redirecionamento 301 (URL de destino final correto):
DE:
https://www.example.com/index.php?url=courses/acme-course.php
PARA:
https://www.example.com/courses/acme-course
Meu 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>
Responder1
Você tem dois problemas principais....
- Suas diretivas estão na ordem errada no
.htaccess
arquivo. Seu HTTP para HTTPS ewww
redirecionamentos canônicos precisam serantesseu front-controller que encaminha o URL para o seu CMS. Daí o redirecionamento externo incorreto para/index.php?url=courses/acme-course.php
- expondo sua estrutura interna de URL do CMS.
A remoção de
.php
não está realmente sendo realizada pelas suas.htaccess
diretivas?! Presumo que isso deva estar sendo feito pela lógica do seu aplicativo/CMS. Consequentemente, isto irásempreresultará em um segundo redirecionamento (já que.htaccess
está redirecionando para HTTPS no mesmo caminho de URL). Você precisa fazer algo como o seguinte na parte superior do.htaccess
arquivo para remover a.php
extensão.RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]
ATUALIZAR:Se eu reordenar as regras/condições, meu posicionamento de Options +FollowSymlinks permanecerá o mesmo?
Isso realmente não importaondea Options
diretiva ocorre. No entanto, é lógico (do ponto de vista da legibilidade) colocá-lo próximo ao topo. (As diretivas do Apache não são necessariamente executadas na ordem em que aparecem no arquivo de configuração, pois cada módulo funciona de forma independente.)
Supondo que você esteja codificando seu .htaccess
arquivo manualmente, ele pode ser arrumado ...
Não há necessidade de (vários)
<IfModule mod_rewrite.c>
wrappers. O mod_rewrite é opcional? O seu site foi portado para vários servidores onde o mod_rewrite não está habilitado?Não há necessidade de múltiplas
RewriteEngine
diretivas. Odurarinstância na verdadevencee controla o arquivo inteiro.<IfModule>
Blocos múltiplos eRewriteEngine
são típicos de sistemas que são editados automaticamente por código e/ou projetados para funcionar sem edição em vários servidores.
Portanto, seu .htaccess
arquivo deve ser reescrito assim, nesta ordem:
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 Adicionais:
A
PROTO
variável de ambiente contém qualquer protocolo que esteja sendo solicitado. Com a ordem dos redirecionamentos agora será sempre HTTPS. A razão para essa variável é que o CMS pode redirecionar para HTTP se HTTP for acessado ou HTTPS se HTTPS for acessado. Se você está forçando HTTPS, isso realmente não se aplica. (Embora este env var ainda possa ser usado pelo seu aplicativo.)Raramente você deve usar o
NC
sinalizador em uma condição negada. Daí porque eu o removi da condição!^www\.
. Você deseja que ele redirecione quando o host não iniciar comwww.
- tudo em letras minúsculas. Com oNC
sinalizador, não será possível redirecionarWwW.
- embora isso seja muito raro de qualquer maneira.Removi a verificação desnecessária de HTTPS no redirecionamento canônico www.
O
PT
sinalizador no últimoRewriteRule
não é obrigatório no.htaccess
. Em.htaccess
é o comportamento padrão (passagem).Você precisará limpar o cache do navegador antes de testar, pois os redirecionamentos 301 errados provavelmente terão sido armazenados em cache pelo navegador. É uma boa ideia testar redirecionamentos 302 (temporários) por esse motivo.