为什么 $_SERVER['HTTP_HOST'] 有时是 example.com,有时是 example.com:443?

TRi*_*RiG 4 php apache2

这是一个在 Apache 上运行 PHP 7 的 Ubuntu 服务器,带有一个强制执行 TLS(使用标准端口)的网站。据我了解,https://example.comhttps://example.com:443是完全等价的(事实上,在我的浏览器中,当我输入端口号时,端口号会从地址栏中消失)。然而HTTP_HOST 通常只包含域名,但有时也包含端口号。这可能适用于机器人访问者(我还没有分析日志),但即便如此,我也不知道如何做到。有什么实际区别吗?

(这会导致一些问题,因为我们的一些日志和工作队列以及服务器端缓存是由 分隔开的HTTP_HOST,因此在不同主机上拥有相同的站点报告会令人困惑。)

Mic*_*ton 6

PHP文档指出$_SERVER['HTTP_HOST']

Host的内容当前请求的标头(如果有)。

事实上,该关联数组中的每个变量(其键以字符串开头)HTTP_都是用户代理发送的相应 HTTP 请求变量的副本。

那么,为什么它有时包含主机名,有时同时包含主机名和端口号?

事实证明,这两种语法都是合法且等效的。如果服务器使用非默认端口,则端口号是必需的,否则是可选的。

在什么情况下用户代理会发送端口号(即使它是默认端口号)?

RFC 7230 第 5.4 节解释了 Host: 标头的值是 URI 的权限组件的精确副本。

如果目标 URI 包含权限组件,则客户端必须发送与该权限组件相同的主机字段值,不包括任何 userinfo 子组件及其“@”分隔符。。。

什么是权威成分?

这来自RFC 3986 第 3.2 节中 URI 的定义,其中解释说它是用户信息(用户名和密码)、主机和端口。它解释了如果端口是默认端口,则应省略该端口,但“SHOULD”不等于“MUST”。(参见RFC 2119。

因此,总而言之,如果端口号也出现在 URI 中,则用户代理应在 Host: 标头中发送端口号。因此,如果用户代理有 URL https://example.com:443/robots.txt,那么它将有一个 header Host: example.com:443。用户代理如何获得这样的 URL,没有真正的方法可以告诉。它可能是由您的应用程序发送的,也可能是由用户代理构建的。

RFC 7230 第 2.7.3 节解释了 URL 规范化,在这种情况下,它表示不包含端口号的 URL 和包含默认端口号的 URL 是等效的。


TL;DR:您的应用程序必须预期端口号可能会出现在此标头中,并以适合其使用上下文的某种方式对其进行处理。

您可以考虑使用,它包含处理请求的Apache 中指令$_SERVER['SERVER_NAME']的值(或者,对于 nginx,是块中的第一个指令)。ServerName<VirtualHost>server_nameserver