$_SERVER['HTTPS']
总是空的,但是$_SERVER['HTTP_X_FORWARDED_PROTO']
当我在 https 页面时返回 https
这告诉您,您的 SSL 是由前端代理服务器管理的,而不是您的应用程序服务器。您的应用程序服务器似乎没有安装 SSL 证书,并且很可能通过端口 80 向代理服务器提供普通 HTTP 请求。然后,代理服务器将安全的 HTTPS 响应返回给客户端,因此客户端请求是安全的。
这意味着如果你的应用服务器尝试通过简单地检查标准服务器变量(即HTTPS
or SERVER_PORT
)那么这可能会因重定向循环而失败,因为HTTPS
总是off and SERVER_PORT
始终为 80 - 即使在重定向之后也是如此。 (请注意,HTTPS
Apache 变量可能处于“关闭”状态,但这通常会转换为 PHP 超全局变量$_SERVER['HTTPS']
那是empty- 这就是 PHP 处理它的方式。)
请注意,HTTP 到 HTTPS 的重定向可以在前端代理中执行,甚至在它到达应用程序服务器之前。 (Cloudflare 通过其页面规则.)
或者,您可以检查代理服务器在请求时设置的附加 HTTP 请求标头转发的从代理到您的应用程序服务器。这X-Forwarded-Proto
header(由 PHP 存储为$_SERVER['HTTP_X_FORWARDED_PROTO']
)由代理服务器设置,告诉您客户端使用什么协议连接到您的代理。
因此,将规范重定向结合在一起:
# www to non-www redirect
RewriteCond %{HTTP_HOST} !^example\.com
RewriteRule (.*) https://example.com/$1 [R=301,L]
# http to https redirect
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
根据您发布的指令的格式,www 到非 www 的重定向应该首先出现,以避免请求时出现双重重定向http://www.example.com
(即 HTTP 和 www)。
请注意,只有当您位于处理 SSL 的代理服务器后面时,才应使用这种类型的 HTTP 到 HTTPS 重定向。否则,X-Forwarded-Proto
HTTP 请求标头可能会被恶意客户端请求伪造(但是,这应该由您的代理服务器处理)。
如果您愿意,可以将这两条规则合并为 1 条规则:
# Canonical redirect (no-www and HTTPS)
RewriteCond %{HTTP_HOST} !^example\.com [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://example.com/$1 [R=301,L]