我想在我的网站上做三件事:
- 当用户访问 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
( ) 标志。如果没有该标志,处理将继续进行,并被随后的内部重写捕获。last
L
例如:
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 参数 - 它们都将被丢弃。
这还假设p
URL 参数始终出现在查询字符串的开头(根据您的重写)。
通过在代换字符串我们避免与请求 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]