nginx获取代理服务ip及客户端真实ip

一、问题背景
  在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用 request.getRemoteAddr() 就可以获取到客户端ip,但是当我们使用了nginx 作为反向代理后,使用 request.getRemoteAddr() 获取到的就一直是nginx 服务器的ip的地址,那这时应该怎么办?

首先,一个请求肯定是可以分为请求头和请求体的,而我们客户端的IP地址信息一般都是存储在请求头里的。如果你的服务器有用Nginx做负载均衡的话,你需要在你的location里面配置X-Real-IP和X-Forwarded-For请求头:

二、proxy_set_header 语法
  语法:

proxy_set_header field value;

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

在 java端,需要获取proxy_set_header的参数时,需要使用request.getHeader(field),一般用来获取真实ip地址。

总结:proxy_set_header 就是可设置请求头,并将头信息传递到服务器端。不属于请求头的参数中也需要传递时重定义下就行啦。

三、X-Real-IP
在《实战nginx》中,有这么一句话:

经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址。

这句话的意思是说,当你使用了nginx反向服务器后,在web端使用request.getRemoteAddr()(本质上就是获取 r e m o t e a d d r ) , 取 得 的 是 n g i n x 的 地 址 , 即 remote_addr),取得的是nginx的地址,即 remoteaddr),取得的是nginx的地址,即remote_addr变量中封装的是nginx的地址,当然是没法获得用户的真实ip的。

但是 nginx 是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx里作一个赋值操作,即我在上面的配置:

proxy_set_header X-Real-IP r e m o t e a d d r ;     remote_addr;    remoteaddr;  remote_addr 只能获取到与服务器本身直连的上层请求ip,所以设置$remote_addr一般都是设置第一个代理上面。当一个请求通过多个代理服务器时,用户的IP将会被代理服务器IP覆盖

扫描二维码关注公众号,回复: 14428953 查看本文章
// 在第一个代理服务器中设置
set x_real_ip=$remote_addr
// 最后一个代理服务器中获取
$x_real_ip=IP1

但是问题是,有时候是通过 cdn 访问过来的,那么后面web服务器获取到的永远都是 cdn 的 ip 而非真实用户 ip。那么这个时候就要用到X-Forwarded-For —— 这个变量的意思其实就像是链路反追踪,从客户的真实ip为起点,穿过多层级的proxy ,最终到达web 服务器,都会记录下来,所以在获取用户真实ip的时候,一般就可以设置成

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

这样就能获取所有的代理 ip 和客户 ip。

四、X-Forwarded-For
  X-Forwarded-For 变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是 client1,proxy1,proxy2,以逗号隔开各个地址,由于它是非rfc标准,所以默认是没有的,需要强制添加。

在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip 。也就是说在默认情况下我们使用request.getAttribute(“X-Forwarded-For”)获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,我们需要自己在nginx添加配置:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

意思是增加一个KaTeX parse error: Double subscript at position 12: proxy_add_x_forwarded_for到X…proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute(“X-Forwarded-For”)获得的将会是客户端ip和第一台nginx的ip。

五、KaTeX parse error: Double subscript at position 12: proxy_add_x_forwarded_for又是…proxy_add_x_forwarded_for变量包含客户端请求头中的 X-Forwarded-For 与 $remote_addr两部分,他们之间用逗号分开。

举个例子,有一个web应用,在它之前通过了两个nginx转发,www.***.com 即用户访问该web通过两台 nginx。

在第一台 nginx 中使用:proxy_set_header X-Forwarded-For KaTeX parse error: Double subscript at position 12: proxy_add_x_forwarded_for;,…proxy_add_x_forwarded_for变量的X-Forwarded-For部分是空的,所以只有 r e m o t e a d d r , 而 remote_addr,而 remoteaddr,而remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。

到了第二台nginx,使用:proxy_set_header X-Forwarded-For KaTeX parse error: Double subscript at position 12: proxy_add_x_forwarded_for;,…proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”,这样就清楚了吧。

总结:获取客户端的IP地址不仅可以通过proxy_set_header X-real-ip $remote_addr;获取到,也可以通过proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
示例如下:
1、配置localtion

        location /api {
                limit_req zone=allipse burst=24000 nodelay;
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Headers' 'x-requested-with,content-type';
                proxy_pass http://api;
                proxy_set_header   Host    $host;
                proxy_set_header   Remote_Addr    $remote_addr;
                proxy_set_header   X-Real-IP    $remote_addr;
                proxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;
        }

2、添加log配置

log_format  main  '客户端真实ip: $proxy_add_x_forwarded_for - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$geoip2_data_country_code" "$geoip2_data_country_name" "$geoip2_data_city_name" "$upstream_addr" "$request_time" "$upstream_response_time"';

3、查询日志输出
在这里插入图片描述

先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

猜你喜欢

转载自blog.csdn.net/m0_67391518/article/details/126113738