$host

$host 变量的官方解释

$host:in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request

host 变量的值按照如下优先级获得:

  1. 请求行中的 host
  2. 请求头中的 Host 头部
  3. 与一条请求匹配的 server name

    什么是请求行中的 host

    我们知道,HTTP 是一个文本协议,建立在一个可靠的传输层协议之上。这个传输层协议要是可靠的,面向连接的。由于 TCP 的普及程度,让它成了 HTTP 下层协议事现上的标准。但我们要知道,HTTP 并不仅限于建立在 TCP 之上。只要是可靠的,面向连接的传输层协议,都可以用来传输 HTTP。下面所说的 HTTP,都是指搭载在 TCP 之上的 HTTP。

一个 HTTP 请求过程是这样的,客户端先与服务器建立起 TCP 连接,然后再与服务器端进行请求和回复的收发。请求包含请求行、请求头和请求体,其中,根据请求方法的不同,请求体是可选的。

在发送请求行之前,客户端与服务器已经建立了连接。所以此时请求行中并不需要有服务器的信息。我们用 telnet 测试, 例如:

  1. GET /index.php HTTP/1.1

这就是一个完整的 HTTP 请求行。虽然请求行中不需要有服务器的信息,但仍然可以在请求行中包含服务器的信息。例如:

  1. GET www.test.info/index.php HTTP/1.1

两者一比较,就很容易理解什么叫请求行中的 host 了。第一个请求行中,就没有 host,第二种请求行中,就带了 host,为 www.test.info

Host 请求头与 HTTP/1.0、HTTP/1.1

一个请求,请求行下面就是一些列的请求头。这些请求头,在 HTTP/1.0 中,都是可选的,且 HTTP/1.0 不支持 Host 请求头;而在 HTTP/1.1 中,Host 请求头部必须存在,否则会返回 400 Bad Request
我们看个例子, 使用 telnet 连接:

  1. GET /index.php HTTP/1.1
  2. HTTP/1.1 400 Bad Request
  3. Server: nginx/1.4.6 (Ubuntu)

但是 HTTP/1.0 是不支持 Host 头部的, 所以请求, 不需要带这个 Host, 我们也测试一下:

  1. HEAD /rec/app/detail/youxidaren.html HTTP/1.0
  2. HTTP/1.1 404 NOT FOUND
  3. Server: nginx/1.4.6 (Ubuntu)

可以看到没有返回 400, 而是返回了 404,说明这个请求还是来到 nginx 处理,命中了其中一个配置的 “虚拟主机”, 我到 nginx 下面看 access_log,看到日志写在了第一个的 nginx 虚拟主机配置的日志文件下面,说明 http1.0 情况下,没有带 host 头部,请求默认来到了 nginx 第一个虚拟主机下处理。

什么是与请求匹配的 server name

server name 是指在 Nginx 配置文件中,在 server 块中,用 server_name 指令设置的值。一个 server 可以多次使用 server_name 指令,来实现俗称的 “虚拟主机”。例如:

  1. server {
  2. listen 80;
  3. server_name example.org www.example.org;
  4. ...
  5. }
  6. server {
  7. listen 80;
  8. server_name example.net www.example.net;
  9. ...
  10. }
  11. server {
  12. listen 80;
  13. server_name example.com www.example.com;
  14. ...
  15. }

关于虚拟主机的确定方法,还是引用 Nginx 的官方文档:

  1. server {
  2. listen 80 default_server;
  3. server_name example.net www.example.net;
  4. }

在这个配置中,nginx 仅仅检查请求的 “Host” 头以决定该请求应由哪个虚拟主机来处理。如果 Host 头没有匹配任意一个虚拟主机,或者请求中根本没有包含 Host 头,那 nginx 会将请求分发到定义在此端口上的默认虚拟主机。在以上配置中,第一个被列出的虚拟主机即 nginx 的默认虚拟主机——这是 nginx 的默认行为。而且,可以显式地设置某个主机为默认虚拟主机,即在”listen”指令中设置”default_server” 参数:

$http_host、$host、$proxy_host的区别

变量 说明 是否显示端口 值是否存在
http_host 从URL中截取 “Host:value”,value存在就显示
host 无 Host 传入, 则使用其 server_name 的第一项 “Host:value”显示。
值为a:b的时候,只显示a
proxy_host 取自于 proxy_pass 的参数 默认80不显示,其他端口显示 “Host:value”显示

硬编码$host

当请求经过nginx的时候,我们可以选择把 $host 变量原封不动传递下去,也可以在此修改它的值。
因为有些程序会对 Host 签名,如果 URL 修改过一个字符(host一般从URL中获取),就会被认为签名错误,所以我们必须在 nginx 中修改 Host。如下:

  1. server {
  2. listen 9000;
  3. location / {
  4. proxy_set_header X-Real-IP $remote_addr;
  5. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  6. proxy_set_header X-Forwarded-Proto $scheme;
  7. proxy_set_header Host '192.168.139.130:9000';
  8. proxy_connect_timeout 300;
  9. # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
  10. proxy_http_version 1.1;
  11. proxy_set_header Connection "";
  12. chunked_transfer_encoding off;
  13. proxy_pass http://192.168.139.130:9000;
  14. }
  15. }

我们在上面设置了:

  1. proxy_set_header Host '192.168.139.130:9000';

表明我们需要修改 Host 变量的值,把它修改为 192.168.139.130:9000


https://www.jianshu.com/p/0850db5af284