在 .htaccess 重定向中保留 HTTP/HTTPS 协议
Posted
技术标签:
【中文标题】在 .htaccess 重定向中保留 HTTP/HTTPS 协议【英文标题】:Preserve HTTP/HTTPS protocol in .htaccess redirects 【发布时间】:2013-10-22 17:57:17 【问题描述】:我必须在 htaccess 中将端口 80 重定向到 2368,但我想保持请求的协议完好无损,以免 SSL 中断。
我目前有这个:
RewriteCond %HTTP_HOST ^sub.domain.com$ [NC]
RewriteRule ^ http://sub.domain.com:2368%REQUEST_URI [P,QSA,L]
这可以正常工作,但如果可能,我希望从 %HTTP_HOST 条件中获取协议。
有没有办法在没有硬编码域和协议的情况下让它变得更加动态?
看起来很慢。
【问题讨论】:
【参考方案1】:Jon 提供的技巧是一个不错的 hack,但如果你想使用更多 [OR]
条件,我担心它可能会崩溃,如果你使用更多反向引用,你必须小心使用哪个数字 (%1
或%2
或..)。
我认为smart HTTP/HTTPS handling 最优雅、健壮和干净的解决方案是设置一个变量:
# initialization code - put only once at the beginning of .htaccess
RewriteCond %HTTPS =on
RewriteRule ^(.*)$ - [env=proto:https]
RewriteCond %HTTPS !=on
RewriteRule ^(.*)$ - [env=proto:http]
# simply use %ENV:proto in your rules:
RewriteCond %HTTP_HOST ^sub.domain.com$ [NC]
RewriteRule ^ %ENV:proto://sub.domain.com:2368%REQUEST_URI [P,QSA,L]
优点也是初始化代码只需要运行一次,所以如果你有更多的重写规则,那么生成的代码会更短更优雅。
请注意,常见的设置是 cloudflare 提供的 https,在这种情况下,HTTPS 在服务器本身上不是“开启”的。在这种情况下,您需要额外的规则,例如(注意顺序):
RewriteCond %HTTP:CF-Visitor '"scheme":"http"' [OR]
RewriteCond %HTTPS !=on
RewriteRule ^(.*)$ - [env=proto:http]
RewriteCond %HTTP:CF-Visitor '"scheme":"https"' [OR]
RewriteCond %HTTPS =on
RewriteRule ^(.*)$ - [env=proto:https]
【讨论】:
就我而言,它是%ENV:HTTPS
,但除此之外,太棒了!对于调试,您只需将 #%HTTPS-%ENV:HTTPS-%ENV:proto
附加到重定向目标并查看它的去向。
设置环境变量 (^(.*)$
) 的 RewriteRules 中的正则表达式变量 match 和 group 过多,应该删除,因为它实际上并没有在之后使用,而是使用破折号 (-)简单地通过。因此,例如,您只需要RewriteRule . - [env=...]
或类似名称。
将原型保存在环境中是一个非常好的主意。当您需要多个 RewriteCond 反向引用时,这很有效,但显然这不起作用。【参考方案2】:
从 Apache 2.4 开始,您还可以使用变量 %REQUEST_SCHEME
来保留方案:
RewriteRule "^" "%REQUEST_SCHEME://sub.domain.com:2368%REQUEST_URI" [P,QSA,L]
这样就不用多管闲事了。
【讨论】:
【参考方案3】:尝试添加如下条件:
RewriteCond %HTTPS off [OR]
RewriteCond %HTTPS:s on:(s)
检查 HTTPS 是关闭还是打开,您可以使用反向引用来获取“s”字符:
RewriteCond %HTTP_HOST ^sub.domain.com$ [NC]
RewriteCond %HTTPS off [OR]
RewriteCond %HTTPS:s on:(s)
RewriteRule ^ http%1://sub.domain.com:2368%REQUEST_URI [P,QSA,L]
所以如果 HTTPS 关闭,%1
为空白,协议为 http://
。如果 HTTPS 开启,则“s”被分组,%1
反向引用为“s”,因此协议为 https://
。
不过,这一切都假设端口 2368 可以处理未加密和 SSL/TLS。
【讨论】:
只是一个小评论。这不是重定向,这是由充当代理(P 标志)的服务器解决的。要进行实际重定向并要求客户端转到另一个 URL,您应该使用 R 标志而不是 P。【参考方案4】:或者,您可以使用the solution posted as an answer by Jon Lin 并将其重写为使用一个RewriteCond
,然后设置一个变量as suggested in the answer by TMS。
看起来像这样:
RewriteCond %HTTPSs ^(on(s)|offs)$
RewriteRule ^ - [env=s:%2]
RewriteCond %HTTP_HOST ^sub.domain.com$ [NC]
RewriteRule ^ http%ENV:s://sub.domain.com:2368%REQUEST_URI [P,QSA,L]
或者,如果您愿意:
RewriteCond %HTTPSs ^(on(s)|offs)$
RewriteRule ^ - [env=proto:http%2]
RewriteCond %HTTP_HOST ^sub.domain.com$ [NC]
RewriteRule ^ %ENV:proto://sub.domain.com:2368%REQUEST_URI [P,QSA,L]
【讨论】:
^(on(s)|offs)$
- 您可以将此正则表达式“简化”为 ^on(s)|
并改用 %1
。【参考方案5】:
http 到 https 的重定向:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %HTTPS !on
RewriteRule ^(.*)$ https://%SERVER_NAME%REQUEST_URI [R=301,L]
</IfModule>
非 www 到 www 重定向:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %HTTP_HOST !^www\. [NC]
RewriteRule ^(.*)$ https://www.%HTTP_HOST/$1 [R=301,L]
</IfModule>
如果你想同时使用这两个功能,那么将这两个代码块放在上面 适当的。
【讨论】:
虽然这不是问题所要求的。以上是关于在 .htaccess 重定向中保留 HTTP/HTTPS 协议的主要内容,如果未能解决你的问题,请参考以下文章
.htaccess:将根URL重定向到子目录,但保留根URL