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]

相关推荐
寻星探路18 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
王达舒199418 小时前
HTTP vs HTTPS: 终极解析,保护你的数据究竟有多重要?
网络协议·http·https
朱皮皮呀18 小时前
HTTPS的工作过程
网络协议·http·https
Binary-Jeff19 小时前
一文读懂 HTTPS 协议及其工作流程
网络协议·web安全·http·https
七夜zippoe1 天前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
Fcy6481 天前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满1 天前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠1 天前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Harvey9031 天前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
珠海西格电力科技1 天前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市