因此,我最近更新了 .htaccess,使用 308(而不是 Apache 通常使用的 301)复制目录斜杠指令,以便浏览器重复相同的请求,而不是将其更改为 GET 请求并从其他请求方法中删除数据。
# Disable
DirectorySlash Off
# Recreate the DirectorySlash directive with 308
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ /$1/ [R=308,L]
这在我的本地测试中效果很好,但是当我使用使用 HTTPS 的测试服务器时,它突然崩溃了。 在 Chrome 开发工具中,我可以看到它被定向到不安全的 url 或某种原因。
错误:
Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://...'. This request has been blocked; the content must be served over HTTPS.
我也尝试过像这样添加请求方案,但没有效果。
RewriteRule ^(.+[^/])$ %{REQUEST_SCHEME}://%{HTTP_HOST}/$1/ [R=308,L]
有谁知道为什么 Apache 将协议更改为不安全的协议吗?
更新: 我尝试检查协议并将其存储在变量中,因为 REQUEST_SCHEME 并不总是定义并导致它再次默认返回 http。
RewriteCond %{HTTPS} on
RewriteRule .* - [E=PROTO:https]
RewriteCond %{HTTPS} !on
RewriteRule .* - [E=PROTO:http]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ %{ENV:PROTO}://%{HTTP_HOST}/$1/ [R=308,L]
这最初似乎有效,但当请求是 POST 时,它仍然将 HTTPS 重定向到 HTTP。
更新:正如 arkascha 建议的那样,我尝试硬编码 HTTPS,这有效。
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ https://%{HTTP_HOST}/$1/ [R=308,L]
这非常奇怪,因为变量方法应该产生相同的结果。初始请求是 HTTPS,因此变量最终应使用 HTTPS,就像硬编码方法一样。
所以我想我必须使用基于域的检查或其他一些解决方法,并复制 HTTP 与 HTTPS 的逻辑。
我觉得这对于让 308 重定向按照记录工作来说都是不必要的。
任何人都可以解释这种奇怪的行为吗?
我突然想到,如果
RewriteCond %{HTTPS} on
或 %{REQUEST_SCHEME}
的行为就像请求是 HTTP 一样,那么这意味着 Apache 一定会以某种方式接收 HTTP 请求,无论初始协议如何。
测试服务器由AWS托管,似乎HTTPS请求必须由AWS解密,然后以未加密的方式发送到Apache实例。 (我不知道这个服务器最初是如何设置的)。
解决方案是检查
X-Forarded-Proto
并设置要在重定向中使用的变量:
# Assume HTTP by default for local devs.
RewriteRule .* - [E=PROTO:http]
# Change to HTTPS if forwarded/current request is HTTPS.
RewriteCond %{HTTP:X-Forwarded-Proto} =https [OR]
RewriteCond %{HTTPS} on
RewriteRule .* - [E=PROTO:https]
# Recreate the DirectorySlash directive with 308
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ %{ENV:PROTO}://%{HTTP_HOST}/$1/ [R=308,L]
至于为什么这只是我的 POST 308 重定向,我唯一的理论是,当它是 GET 请求时,浏览器会默默地为我们更正协议,如果它不是 GET 请求,则更严格地遵循 308 指令。 否则,GET 请求应该也会出现同样的问题。
如果有人可以更详细地解释,特别是浏览器的行为(Chrome && Firefox),我很乐意接受另一个答案。