概述

我们在做nginx方向代理的时候,为了记录整个代理过程,我们往往会在配置文件中加上如下配置:

location ^~ /app/download/ {
...
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
proxy_pass http://10.1.10.203:8080;
}

proxy_set_header就是记录整个代理过程的配置。其中X-Forwarded-For(XFF)位于HTTP请求头,已经成为事实上的标准。
XFF的请求格式很简单,如下:

X-Forwarded-For: client, proxy1, proxy2

由上面可以看到XFF的的内容由[IP+英文逗号+空格]组成(如果有多个代理的话),最开始的client是客户端的IP,proxy1和proxy2分别是一级代理和二级代理的IP。
假设代理如下:

如上,proxy1、proxy2和proxy3都用NG做反代,并且在它们的配置上都加上如下配置:

proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

那么在Real Server(NG的WEB容器)上打印的日志(日志里带$http_x_forwarded_for)就会带有IP0,IP1,IP2的HTTP头,可以看到没有IP3,因为IP3是直连服务器,它会给XFF追加IP2的地址,表示它是帮proxy2做转发的,Real Server要获取IP3的地址,需通过remote Address字段获得。
同理,在proxy3上日志里只会有IP0和IP1,proxy2上日志里只有IP0,proxy1上没有IP。

测试

测试拓扑如下:

在proxy1上的配置如下:

    server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html; # Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf; location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.169.130/;
}
}

在proxy2上的配置如下:

    server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html; # Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf; location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.169.131/;
}
}

在proxy3的配置如下:

    server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html; # Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf; location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://xxx.xxx.xxx.xxx:8888/;
}
}

proxy1,proxy2,proxy3上的日志格式如下:

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

Real Server日志格式如下:

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

我在本机浏览器输入:http://192.168.169.128/,然后分别在proxy1-3还有Real Server上抓取nginx日志,proxy1-3日志最后一个字段是$http_x_forwarded_for,Real Server倒数二个字段是$http_x_forwarded_for如下:
proxy1日志:

192.168.169.1 - - [04/Jun/2019:10:57:06 +0800] "GET / HTTP/1.1" 200 20 "-"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/74.0.3729.169 Safari/537.36" "-"

proxy2日志:

192.168.169.128 - - [04/Jun/2019:10:57:06 +0800] "GET / HTTP/1.0" 200 10 "-"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/74.0.3729.169 Safari/537.36" "192.168.169.1"

proxy3日志:

192.168.169.130 - - [29/Mar/2019:23:29:36 +0800] "GET / HTTP/1.0" 200 10 "-"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/74.0.3729.169 Safari/537.36" "192.168.169.1, 192.168.169.128"

Real Server日志:

183.66.224.50 - - [04/Jun/2019:10:57:03 +0800] "GET / HTTP/1.0" 200 10 - "-"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/74.0.3729.169 Safari/537.36" "==192.168.169.1, 192.168.169.128, 192.168.169.130" "---"

从上面的日志可以知道:
(1)、设置X-Forwarded-For是一个可叠加的过程;
(2)、后端服务器XFF获取不到直连服务器IP。比如Real-Server的日志中XFF字段没有proxy3的IP地址,依次类推;
(3)、代理中要配置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

HTTP请求头中的X-Forwarded-For介绍的更多相关文章

  1. HTTP 请求头中的 X-Forwarded-For(转)

    原文:https://imququ.com/post/x-forwarded-for-header-in-http.html 我一直认为,对于从事 Web 前端开发的同学来说,HTTP 协议以及其他常 ...

  2. Http 请求头中的 Proxy-Connection

    平时用 Chrome 开发者工具抓包时,经常会见到 Proxy-Connection 这个请求头.之前一直没去了解什么情况下会产生它,也没去了解它有什么含义.最近看完<HTTP 权威指南> ...

  3. js 中ajax请求时设置 http请求头中的x-requestd-with= ajax

    今天发现 AngularJS 框架的$http服务提供的$http.get() /$http.post()的ajax请求中没有带 x-requested-with字段. 这样的话,后端的php 就无法 ...

  4. HTTP 请求头中的 Remote_Addr,X-Forwarded-For,X-Real-IP

    REMOTE_ADDR 表示发出请求的远程主机的 IP 地址,remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间 ...

  5. shiro + jwt 实现 请求头中的 rememberMe 时间限制功能

    前言: 上一篇提出, 通过修改 rememberMe 的编码来实现 rememberMe的功能的设想, 事后我去尝试实现了一番, 发现太麻烦, 还是不要那么做吧. 程序还是要越简单越好. 那功能总是要 ...

  6. shiro 获取请求头中的 rememberMe

    前言: 上一篇提到了, 将 sessionId 放到请求头中去, 那rememberMe是否也可以放到请求头中去呢. 其实不管是sessionId还是rememberMe, shiro都会默认往coo ...

  7. shiro 获取请求头中的 sessionId

    前言: 在前后端项目中, 前端有可能会要求, 后台返回一个 sessionId 给他, 然后他在请求后台接口时, 把这个sessionId 带给后台, 后台拿到这个sessionId , 就能识别, ...

  8. Ajax 请求头中常见content-type

    四种常见的 POST 提交数据方式 HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范.规范把 HTTP 请求分为三个部分:状态行.请求头.消息主体.协议规定 POST ...

  9. WebAPi获取请求头中对应键值

    /// <summary> /// 依据键获取请求头中值数据 /// </summary> /// <param name="request"> ...

  10. 使用zuul实现验证自定义请求头中的token

    路由:她会把外部所有对请求转发到具体的微服务实例上,是实现外部访问同一接口的基础 过滤: 就是权限的检查, 判断当前的请求是否有权限区访问那些服务集群 搭建后台网关: 导入eureka - clien ...

随机推荐

  1. Struts2-学习笔记系列(5)-配置action

    配置包命名空间 实现了action就需要在struts中配置action.首先配置包属性: 需要注意的是:在框架进行包匹配的时候,按文档的从上到下的顺序进行匹配   <!--下面配置名为book ...

  2. excel中存储的时间的类型是什么

    做了一个excel导入数据的功能,其中需要导入时间,默认到天.在开发过程中发现了一个问题, 导入的数据解析到的时间格式是 02-03-19,发现年份前面的两位数丢失了.这当然是导入数据 的解析包的问题 ...

  3. Android MonkeyTalk测试

    Android MonkeyTalk测试 MonkeyTalk可以用于压力测试,正因为这点所以才选择MonkeyTalk进行测试,相对于Monkey测试,目前个人发现的有点在于,MonkeyTalk是 ...

  4. 假的数论gcd,真的记忆化搜索(Codeforce 1070- A. Find a Number)

    题目链接: 原题:http://codeforces.com/problemset/problem/1070/A 翻译过的训练题:https://vjudge.net/contest/361183#p ...

  5. 泛型方法或泛型类中的方法是内部调用、PInvoke 或是在 COM 导入类中定义的。

    泛型基类中引用Api函数定义时static extern,在子类中会提示: 未处理TypeLoadException 泛型方法或泛型类中的方法是内部调用.PInvoke 或是在 COM 导入类中定义的 ...

  6. First Training

    B B - Local Extrema CodeForces - 888A You are given an array a. Some element of this array ai is a l ...

  7. docker环境常用命令

    Ubuntu 安装docker及docker-compose 安装: apt-get install docker apt-get install docker-compose 启动docker环境: ...

  8. 彻底弄懂GMT、UTC、时区和夏令时

    前言 格林威治时间.世界时.祖鲁时间.GMT.UTC.跨时区.夏令时,这些眼花缭乱的时间术语,我们可能都不陌生,但是真正遇到问题,可能又不那么确定,不得不再去查一查,处理完可能过段时间又忘记.今天,我 ...

  9. java Int类型转为double 类型;string转double

    int a=12; double b=(double)a; or double c=Double.valueOf((double)a); string a_s="12"; doub ...

  10. Linux下jdk的安装和环境变量的配置

    Linux下jdk的安装和环境变量的配置 一.jdk的下载 方式一:在官网下载 http://www.oracle.com/technetwork/java/javase/downloads/inde ...