在 .htaccess 中处理 301 重定向和内部重写

在 .htaccess 中处理 301 重定向和内部重写

我想在我的网站上做三件事:

  • 当用户访问 HTTP 版本时,使用 301 将用户重定向到网站的 HTTPS 版本
  • www当用户在 URL 中输入 www 时,使用 301 重定向到网站的“无 www”版本
  • 静默地(或内部地)重定向/*/index.php?p=*(因为我正在使用框架)。(或者甚至“视觉上”重定向/index.php?p=*/*,然后内部重定向/*/index.php?p=*...)

这是我当前的.htaccess:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule (.*) https://%1/$1 [R=301]

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.php?p=$1 [QSA]
</IfModule>

但是当我运行此配置时,我的 301 重定向不起作用——更准确地说,301 代码实际上已发送给客户端,但没有Location:发送标头:

$ curl http://mywebsite.com/path -I
HTTP/1.1 301 Moved Permanently
Date: Thu, 23 Apr 2020 19:03:57 GMT
Server: Apache/2.4.38 (Debian)
Set-Cookie: ci_session=q24j0enjrskagec2fggi256bpg5fsvs6; expires=Thu, 23-Apr-2020 20:39:57 GMT; Max-Age=7200; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=UTF-8

如果我尝试将该块放在index.php另外两个块之前,HTTPS 和www重定向就可以工作,但是Location:在处理页面时标头会出现奇怪的行为:

λ curl http://mywebsite.com/fr/salon -I
HTTP/1.1 301 Moved Permanently
Date: Thu, 23 Apr 2020 19:09:03 GMT
Server: Apache/2.4.38 (Debian)
Location: https://mywebsite.com/fr/salon?p=fr/salon
Content-Type: text/html; charset=iso-8859-1

(您还可以看到字符集因某些奇怪的原因而发生了变化)

我必须对规则进行哪些更改才能使我的三个重定向正常工作?
谢谢!

答案1

RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule (.*) https://%1/$1 [R=301]

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301]

您的两次重定向均缺少L( ) 标志。如果没有该标志,处理将继续进行,并被随后的内部重写捕获。lastL

例如:

RewriteRule (.*) https://%1/$1 [R=301,L]

更新:L您也应该在以后的重写中严格包含该标志。尽管如果这是最后一次RewriteRule重写,那么这并不重要。但是,如果您以后添加更多规则,那么它可能很重要。

甚至“视觉上”重定向/index.php?p=*/*

仅当您要更改现有 URL 结构时才严格要求此部分,其中老的 index.php?p=URL 被搜索引擎索引或被第三方链接。

此处的重点是通过阻止重写的 URL 被重定向来避免潜在的重定向循环。我们可以通过检查REDIRECT_STATUS环境变量(在初始请求时为空,并设置为“200”,即第一次成功重写后的 200 OK HTTP 状态)来做到这一点。

例如,您现有的重定向,在RewriteBase指令之后,您可以执行如下操作来外部重定向/index.php?p=*/*

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^p=([^&]*)
RewriteRule ^index\.php$ https://example.com/%1 [QSD,R=302,L]

(查询字符串丢弃)标志QSD(Apache 2.4+)对于从p=*请求中删除查询字符串(即 URL 参数)是必需的。这假设您没有其他需要传递的 URL 参数 - 它们都将被丢弃。

这还假设pURL 参数始终出现在查询字符串的开头(根据您的重写)。

通过在代换字符串我们避免与请求 HTTP 或 www 子域相关的任何二次重定向。

请注意,目前这是 302(临时)重定向。最好先使用 302 进行测试,然后再更改为 301(永久)重定向,以避免潜在的缓存问题。

答案2

重写引擎开启
RewriteCond %{HTTPS} 关闭 [或]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
重写规则 ^ https://%1%{REQUEST_URI} [L,NE,R=301]

相关内容