Nginx中$http_host、$host、$proxy_host的区别

知识巩固!

网上看到这篇文章,这里转载记录一下。

简介

变量

是否显示端口

值是否存在

host

浏览器请求的ip,不显示端口

"Host:value"显示

值为a:b的时候,只显示a

http_host

浏览器请求的ip和端口号

"Host:value",value存在就显示

proxy_host

被代理服务的ip和端口号

默认80不显示

其他端口显示

"Host:value"显示

配置反向代理时,接口请求报404问题

应用描述:前端应用域名为A(ww.a.com), 后端服务域名为B(www.b.com); 为了解决跨域问题,配置nginx反向代理如下:

...

proxy_set_header Host KaTeX parse error: Undefined control sequence: \* at position 54: ...write "^/api/(.\̲*̲)" /$1 break;

proxy_pass http://www.b.com;

}

问题:这样配置完成后,接口报404问题。

解决:

方案一:将proxy_set_header注释掉

方案二:修改反向代理配置,设置请求头Host,如下所示:

location ^~ /api/ {

rewrite "^/api/(.*)" /1 break;

proxy_pass http://www.b.com;
proxy_set_header Host $proxy_host; //方式一:设置请求头host为www.b.com的ip和端口号
proxy_set_header Host www.b.com; //方式二:设置请求host为www.b.com

}

nginx中proxy_set_header Host $host的作用

nginx为了实现反向代理的需求而增加了一个ngx_http_proxy_module模块。其中proxy_set_header指令就是该模块需要读取的配置文件。在这里,所有设置的值的含义和http请求体中的含义完全相同,除了Host外还有X-Forward-For。

Host的含义是表明请求的主机名,因为nginx作为反向代理使用,而如果后端真实服务器设置有类似防盗链或者根据http请求头中的host字段来进行路由或判断功能的话,如果反向代理层的nginx不重写请求头中的host字段,将会导致请求失败【默认反向代理服务器会向后端真实服务器发送请求,并且请求头中的host字段应为proxy_pass指令设置的服务器】

同理,X_Forward_For字段表示该条http请求是由谁发起的?如果反向代理服务器不重写该请求头的话,那么后端真实服务器在处理时会认为所有的请求都来在反向代理服务器,如果后端有防攻击策略的话,那么机器就被封掉了。因此,在配置用作反向代理的nginx中一般会增加两条配置,修改http的请求头。

1

2

proxy_set_header Host $http_host;

proxy_set_header X-Forward-For $remote_addr;

这里的 h t t p _ h o s t 和 http\_host和 http_host和remote_addr都是nginx的导出变量,可以在配置文件中直接使用。如果Host请求头部没有出现在请求头中,则 h t t p _ h o s t 值为空,但是 http\_host值为空,但是 http_host值为空,但是host值为主域名。因此,一般而言,会用 h o s t 代替 host代替 host代替http_host变量,从而避免http请求中丢失Host头部的情况下Host不被重写的失误。

X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。 它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。标准格式如下:X-Forwarded-For: client1, proxy1, proxy2。

这一HTTP头一般格式如下:X-Forwarded-For: client1, proxy1, proxy2。其中的值通过一个"逗号+空格"把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。

在上面这个例子中,这个请求成功通过了三台代理服务器:proxy1, proxy2 及 proxy3。请求由client1发出,到达了proxy3(proxy3可能是请求的终点)。请求刚从client1中发出时,XFF是空的,请求被发往proxy1;通过proxy1的时候,client1被添加到XFF中,之后请求被发往proxy2;通过proxy2的时候,proxy1被添加到XFF中,之后请求被发往proxy3;通过proxy3时,proxy2被添加到XFF中,之后请求的的去向不明,如果proxy3不是请求终点,请求会被继续转发。

鉴于伪造这一字段非常容易,应该谨慎使用X-Forwarded-For字段。正常情况下XFF中最后一个IP地址是最后一个代理服务器的IP地址, 这通常是一个比较可靠的信息来源。

proxy_set_header设置Host为 p r o x y _ h o s t , proxy\_host, proxy_host,host与$local_host的区别

先来看下proxy_set_header的语法:**proxy_set_header**?`field``value`;

默认值:

1

2

proxy_set_header Host $proxy_host;

proxy_set_header Connection close;

上下文:http,server,location

作用:允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义:

1

2

proxy_set_header Host?????? $proxy_host;

proxy_set_header Connection close;

nginx对于upstream默认使用的是基于IP的转发,因此对于以下配置:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

upstream backend {?

????????``server 127.0.0.1:8080;?

????``}?

????``upstream crmtest {?

????????``server crmtest.aty.sohuno.com;?

????``}?

????``server {?

????????????``listen?????? 80;?

????????????``server_name? chuan.aty.sohuno.com;?

????????????``proxy_set_header Host $http_host;?

????????????``proxy_set_header x-forwarded-for? $remote_addr;?

????????????``proxy_buffer_size???????? 64k;?

????????????``proxy_buffers???????????? 32 64k;?

????????????``charset utf-8;?

????????????``access_log? logs/host.access.log? main;?

????????????``location = /50x.html {?

????????????????``root?? html;?

????????????``}?

????????``location / {?

????????????``proxy_pass backend ;?

????????``}?

????????``location = /customer/straightcustomer/download {?

????????????``proxy_pass http://crmtest;?

????????????``proxy_set_header Host $proxy_host;?

????????``}?

????``}

当匹配到 /customer/straightcustomer/download时,使用crmtest处理,到upstream就匹配到crmtest.aty.sohuno.com,这里直接转换成IP进行转发了。假如crmtest.aty.sohuno.com是在另一台nginx下配置的,ip为10.22.10.116,则$proxy_host则对应为10.22.10.116。此时相当于设置了Host为10.22.10.116。

1

2

3

4

5

6

7

8

9

10

11

// 如果想让Host是crmtest.aty.sohuno.com,则进行如下设置:

proxy_set_header Host crmtest.aty.sohuno.com;

// 如果不想改变请求头"Host"的值,可以这样来设置:

proxy_set_header Host $http_host;

// 但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。

// 这种情况下,更好的方式是使用$host变量------它的值在请求包含"Host"请求头时为"Host"字段的值,在请求未携带"Host"请求头时为虚拟主机的主域名:

proxy_set_header Host?????? $host;

// 此外,服务器名可以和后端服务器的端口一起传送:

proxy_set_header Host $host:$proxy_port;

// 如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器:

proxy_set_header Accept-Encoding "";

通过Nginx配置演示:

root@ans3 conf# cat nginx.conf

复制代码
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
error_log  logs/error.log  info;
#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;

    server {
       listen       80;
       server_name  a.test.com;

       location / {
            proxy_pass http://10.0.0.50:8080;
            proxy_set_header X-Proxy-Host $proxy_host;
            proxy_set_header Host $http_host;
            index index.html index.htm;
       }
    }
}

另一台服务器配置

root@master conf# cat nginx.conf

复制代码
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       8080;
        server_name  www.test.com aa.test.com;

        location / {
              return 200 'http_host=[$http_host] host=[$host] proxy_host=[$http_x_proxy_host]
';
        }
    }
}

不携带请求头 Host

root@ans3 conf# curl -H 'Host:' --http1.0 http://a.test.com

http_host=\[\]

host=www.test.com

proxy_host=10.0.0.50:8080

变量

说明

http_host

请求无 Host, 则 http_host 为空, 继而无 Host 传到 proxy

host

www.test.com

proxy 无 Host 传入, 则使用其 server_name 的第一项

proxy_host

10.0.0.50:8080

取自于 proxy_pass 的参数

携带请求头 Host

root@ans3 conf# curl -H 'Host🔤123' --http1.0 http://a.test.com

http_host=abc:123

host=abc

proxy_host=10.0.0.50:8080

变量

说明

http_host

abc:123

给啥拿啥

host

abc

第一个:前的内容(小写)

proxy_host

10.0.0.50:8080

带端口显示

修改真实服务器的端口为默认端口

http {

include mime.types;

default_type application/octet-stream;

复制代码
log\_format  main  '$remote\_addr - $remote\_user \[$time\_local\] "$request" '
                  '$status $body\_bytes\_sent "$http\_referer" '
                  '"$http\_user\_agent" "$http\_x\_forwarded\_for"';

access\_log  logs/access.log  main;
sendfile        on;
tcp\_nopush     on;
keepalive\_timeout  65;

server {
    listen  80;
    server\_name  a.test.com;
    
    location / {
        proxy\_pass http://10.0.0.50:80;
        proxy\_set\_header X-Proxy-Host $proxy\_host;
        proxy\_set\_header Host $http\_host;
        index index.html index.htm;
   }

}

}

http {

include mime.types;

default_type application/octet-stream;

复制代码
sendfile        on;
keepalive\_timeout  65;

server {
    listen       80;
    server\_name www.test.com aa.test.com;


    location / {
         return 200 'http\_host=\[$http\_host\] host=\[$host\] proxy\_host= \[$http\_x\_proxy\_host\]

';

}

}

}

访问时proxy_host会省略80端口

root@ans3 conf# curl -H 'Host🔤123' --http1.0 http://a.test.com

http_host=abc:123

host=abc

proxy_host=10.0.0.50

相关推荐
ping某6 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
霜落长河1 天前
抛弃TCP改用UDP,HTTP3怎么了?
http
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工2 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智2 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_2 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉2 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造
之歆2 天前
现代 HTTP 客户端深度解析:Fetch 与 Axios
chrome·网络协议·http