前言
首先:简单的端口 80 -> 端口 443 重写将不会修复此问题。在几乎每个先前的问题、邮件主题、论坛主题等中,我发现这是第一个无知的回应,并且被重复了好几次。
其次:是的,我知道您不能在同一个端口上提供 HTTP 和 HTTPS 流量。 這不是那樣。
设想:
Apache 服务器通过端口复用托管多个站点。端口 80 服务于公共站点。端口 443 服务于该站点的安全版本。
端口 7443、8443 和 9443 分别服务于单独的 SSL 安全站点。
如果用户输入错误的 URL,或者给出无效的链接,则说http://主机名.tld:7443,他们看到的是以下荒谬的页面:
服务器不再只是将访问者重定向到https://主机名.tld:7443。
我的问题是,如何以宙斯的屁眼您可以修改 Apache 的行为或此错误消息以自动重定向用户吗?
Apache 显然正在处理非 https 请求(以显示该错误消息),即使它已配置为 HTTPS。在我看来,不默认进行重定向是非常愚蠢的,但我可以理解他们为什么会这样做,即使我不同意。所以我的问题是:你能改变它吗?他们在某个地方处理错误,而 Apache 是配置的宝库,理所当然地,在某个地方有一些指令来处理这种行为,但我到目前为止在几个小时的修补中都无法找到它。
更新:
我尝试过各种各样的事情,包括:
使用
ErrorDocument 400
指令获取 CGI 和仅发送标头的 PHP 脚本Status 301
。Location
这会导致页面空白。使用ErrorDocument 400 https://hostname.tld:7443
simply 会导致该链接显示在页面上。mod_rewrite
使用我或谷歌能想到的几乎所有组合,包括完全指导网站的笼统声明;这些绝不工作。实际上,它们什么都不做。我推测 Apache 在尝试处理重写指令之前就遇到了上述错误。
由于使用了自定义端口,我无法使用基于端口的重定向。由于 http/https 不匹配,我无法使用基于脚本的重定向,因为它们从未得到服务。我几乎愿意将此归咎于错误或意外行为,但有人有先见之明,在其中放置了一个非常自定义的错误消息,他们没有考虑到您可能只想直接访问 URL他们已经提供了?
答案1
我认为这可能是 Apache 2.2 及更低版本处理这种特殊情况的一个错误。
似乎在 SSL 读取400 Bad Request
错误时,Apache 2.2 不会返回 HTTP 响应代码或标头,而只会返回 HTTP 响应主体。我通过 telnet 到端口 443 并发送以下内容进行测试:
GET / HTTP/1.1
服务器立即返回(对我来说):
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
Instead use the HTTPS scheme to access this URL, please.<br />
<blockquote>Hint: <a href="https://server.tld/"><b>https://server.tld/</b></a></blockquote></p>
</body></html>
请注意缺少 HTTP 响应代码或任何 HTTP 标头。
当我对 Apache 2.4 服务器执行此操作时,我得到:
HTTP/1.1 400 Bad Request
Date: Sun, 10 Feb 2013 00:47:23 GMT
Server: Apache/2.4.3 (Unix) OpenSSL/1.0.0g
Content-Length: 462
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
Instead use the HTTPS scheme to access this URL, please.<br />
</p>
<hr>
<address>Apache/2.4.3 (Unix) OpenSSL/1.0.0g Server at server.tld Port 443</address>
</body></html>
如果我像您一样设置了 ErrorDocument 行:
ErrorDocument 400 https://server.tld/
然后我得到了 302 重定向的 HTML,但同样没有任何标头。如果没有 302 重定向响应代码和标Location:
头,浏览器就不会重定向。
尝试升级到 Apache 2.4,看看是否可行。我至少用 Apache 2.4.3 测试并确认过,但我还没有努力找到这种行为更新的具体时间。我怀疑他们在准备 2.4 时做了大量工作,纠正了这种不良行为作为副作用。
相关的 Apache httpd 错误:
更新
您可以强制有缺陷的 Apache 提供您想要的行为(重定向),方法是让脚本打印出其标头(不会发送到客户端),然后再次手动打印出您想要的标头。以下是在 Apache 2.2.22 下运行的基本 Perl 脚本:
#!/usr/bin/perl
use strict;
use CGI;
my $q = CGI->new();
# this will cause Apache to handle the response properly, but is meaningless otherwise
print $q->redirect("https://localhost/");
# this actually performs the redirect
print "HTTP/1.1 302 Found\r\n";
print "Location: https://localhost/\r\n";
print "\r\n";
# you can do whatever you want here; this will be the HTML body
您应该知道,除了与没有 SSL 的 SSL 端口通信之外,还可能存在其他原因导致 400 错误。确定这一点的简单方法是查找HTTPS
环境变量。如果已设置,则 SSL 已正确协商,并且其他原因导致 400 错误(如果是这种情况,请不要使用双头技巧)。如果HTTPS
未设置,则按上述方式返回重定向。
答案2
你可以用 mod-rewrite 来解决这个问题。设置一个规则来匹配任何内容。请参阅此答案堆栈溢出