Com o Apache, regravar o tráfego para uma pasta e ainda redirecionar todo o tráfego dessa pasta

3

Eu tenho um site que está atualmente migrando de um antigo CMS para um novo (Laravel). Apenas alguns idiomas do site foram transferidos para o Laravel. Então, basicamente, minha pasta raiz do vhost tem algo parecido com isto:

[D] staticContentDirectory1
[D] staticContentDirectory2
...
[D] oldCmsDirectory1
[D] oldCmsDirectory2
...
[D] oldCmsDirectoryN
[D] public
[F] index-of-the-old-cms-still-in-use.php 

Eu tenho um arquivo .htaccess que redireciona tudo o que não é tratado pelo antigo CMS ou em um diretório de conteúdo estático para o Laravel e se parece com isso:

RewriteRule ^((?!staticContentDirectory1|staticContentDirectory2|public)(.*))$ public/$1 [L]

Existe também um .htaccess em público, do Laravel, para lidar com suas coisas.

Até agora, tudo está funcionando perfeitamente e ficamos muito felizes com o resultado (dadas as restrições iniciais).

Descobrimos um problema. De alguma forma, o Google conseguiu descobrir que /public existe e rastreou, o que levou ao URL com /public/ dentro, que desde então criou /public/public/ URLs (que, felizmente, retorna um erro 500 e evitou uma infinidade de URLs).

Antes de corrigir o CMS e robots.txt , tentamos corrigir isso reescrevendo / redirecionando o tráfego de /public para / .

Muitas coisas foram tentadas, muitas falhas aconteceram, quase todas em um loop infinito de redirecionamentos.

Como todo módulo do Apache parece fazer suas coisas sozinho, misturar RedirectMatch e RewriteRule falhou. RewriteCond e RewriteRule eram um redirecionamento infinito ou totalmente ignorado.

TL; DR: Estou pedindo ajuda agora: como é possível ter um RewriteRule para um /folder e ainda redirecionar todo o tráfego dessa pasta para a raiz.

    
por Sebastien F. 13.07.2017 / 12:24

1 resposta

3

Para evitar um loop de redirecionamento, é necessário diferenciar entre uma solicitação direta para o subdiretório /public e uma solicitação que tenha sido reescrita internamente para o subdiretório /public (que é o seu diretiva acima faz).

Existem várias maneiras de fazer isso. Uma maneira é verificar a variável THE_REQUEST server, que contém o cabeçalho da solicitação inicial (por exemplo, GET /public/whatever HTTP/1.1 ) enviada do cliente e não é alterada quando a URL é regravada.

Tente o seguinte ... como regra geral, os redirecionamentos externos devem ser executados antes das reescritas internas, portanto, a regra a seguir deve estar próxima à parte superior do arquivo .htaccess no subdiretório /public (não no arquivo .htaccess na raiz do documento):

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /public
RewriteRule (.*) /$1 [R=302,L]

Para qualquer solicitação direta que inicie /public/<whatever> , redirecione para /<whatever> . A diretiva RewriteCond anterior garante que apenas as solicitações diretas sejam processadas.

A diretiva RewriteRule pode parecer um pouco estranha no início (como se talvez redirecionasse para si mesma), mas isso ocorre porque o padrão RewriteRule corresponde ao caminho da URL menos o prefixo de diretório de onde o arquivo .htaccess está localizado. Assim, dada uma solicitação para /public/<whatever> , a referência de referência $1 captura apenas <whatever> . Então redireciona de volta para /<whatever> .

Observe que este é atualmente um redirecionamento temporário (302). Altere isso para um 301 somente quando tiver certeza de que está funcionando OK. 301s são armazenados em cache pelo navegador, portanto, pode tornar o teste problemático se houver um erro.

mixing RedirectMatch and RewriteRule failed

Como as diretivas pertencem a módulos diferentes (mod_alias vs mod_rewrite), elas são executadas em momentos diferentes durante a requisição, independente da ordem aparente no arquivo de configuração (o mod_rewrite geralmente é executado primeiro). Portanto, misturar essas diretivas pode resultar em conflitos. No entanto, RedirectMatch não fornece o controle necessário nessa instância.

    
por 13.07.2017 / 14:07