在Nginx中,变量$host和$http_host之间的区别是什么?


$host是Core模块的一个变量。

美元的主机

此变量等于请求或报头中的行Host 如果Host头不是,则处理请求的服务器名 可用。

这个变量的值可能与$http_host的值不同 情况:1)当主机输入头不存在或有一个空值时, $host = server_name指令的值;2)当值 的主机包含端口号,$ Host不包含该端口号。 $host的值从0.8.17开始总是小写的。

$http_host也是同一个模块的一个变量,但是你找不到它的名字,因为它一般定义为$http_HEADER (ref)。

http_HEADER美元

HTTP请求头的值,当转换为小写,'破折号'转换为'下划线'时,例如$http_user_agent, $http_referer…;


总结:

$http_host总是等于http_host请求头。 $host等于$http_host,小写,没有端口号(如果存在),除非http_host不存在或为空值。在这种情况下,$host等于处理请求的服务器的server_name指令的值。


公认的答案及其注释似乎(不再)是正确的。文档(http://nginx.org/en/docs/http/ngx_http_core_module.html#var_host)说$host是

按优先级顺序:来自请求行的主机名,或者来自“host”请求报头字段的主机名,或者匹配请求的服务器名

因此$http_host总是Host报头字段的值。如果请求行(如果指定)中的主机与host报头字段不同,则它们可能不同。或者如果没有设置Host报头。

server_name只匹配Host报头字段(http://nginx.org/en/docs/http/request_processing.html),因此$ Host可能与匹配的server_name不同。


http_host美元

$http_host总是等于主机请求报头字段

Host: example.org

美元的主机

$host的优先级顺序(从高到低):

来自请求行的主机名 获取http://example.org/test/ HTTP/1.1 主机请求报头字段 匹配请求的server_name(在Nginx配置中),即使server_name是通配符(Ex: server_name *.example.org;)

来自请求行的主机名

当打开URL http://example.org/test/…

大多数浏览器都是这样发送请求的

GET /test/ HTTP/1.1
Host: example.org

大多数浏览器不会这样发送请求(但这是有效的请求)

GET http://example.org/test/ HTTP/1.1

验证

Nginx测试配置

server {
    listen       80;
    server_name  *.example.org;

    location / {
        default_type "text/plain";
        return 200 "[host] = $host";
    }
}

当一切都存在时……

$host =请求行的主机名

curl http://127.0.0.1 -v \
  --request-target http://request.example.org/test/ \
  --path-as-is \
  -H "Host: host.example.org"

这个命令将

连接到127.0.0.1 发送请求路径为GET http://request.example.org/test/ HTTP/1.1 “主机头”设置为“主机:host.example.org”

*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET http://request.example.org/test/ HTTP/1.1
> Host: host.example.org
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.23.1
< Date: Fri, 21 Oct 2022 02:00:56 GMT
< Content-Type: text/plain
< Content-Length: 28
< Connection: keep-alive
<
* Connection #0 to host 127.0.0.1 left intact
[host] = request.example.org

当只有主机头存在时…

$host =主机头

curl http://127.0.0.1/test/ -v \
  -H "Host: host.example.org"
*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /test/ HTTP/1.1
> Host: host.example.org
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.23.1
< Date: Fri, 21 Oct 2022 02:01:37 GMT
< Content-Type: text/plain
< Content-Length: 25
< Connection: keep-alive
<
* Connection #0 to host 127.0.0.1 left intact
[host] = host.example.org

当不存在时……

$host = server_name(在Nginx配置中)

# HTTP 1.1 must have Host header, so use HTTP 1.0
curl http://127.0.0.1/test/ -v -H "Host:" -0
*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /test/ HTTP/1.0
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.23.1
< Date: Fri, 21 Oct 2022 02:02:20 GMT
< Content-Type: text/plain
< Content-Length: 22
< Connection: close
<
* Closing connection 0
[host] = *.example.org

参考:ngx_http_core_module, Nginx $主机验证