在 .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重定向?

.htaccess 301 重定向,保留路径

htaccess 重定向到新页面但保留“get”参数

.htaccess:将根URL重定向到子目录,但保留根URL

使用 htaccess 重定向页面,但保留 URL 结构并仅更改域

.htaccess 结合 301 重定向和 URI 重写