当nginx作为反向代理功能时,转发请求到后端服务器

通常需要使用如下命令为转发的请求增加请求头 X-Forwarded-For

proxy_set_header X-Forwarded-For "特定的X-Forwarded-For值"

第一版配置:

proxy_set_header X-Forwarded-For $remote_addr;

#如上配置只能增加负载均衡ip地址,丢失了客户端真实ip和任意中间代理ip

第二版配置

proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $remote_addr";

#如上配置在原有请求头X-Forwarded-For字段的基础上增加了连接nginx的服务器ip地址

第三版配置(最为简单)

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

#$proxy_add_x_forwarded_for已经实现了第二版的功能,直接使用该内置变量即可

如果要获取用户端的真实IP,应该从请求头中的 X-Forwarded-For字段中取第一个英文逗号前的ip地址。

第三个配置最为简单,实用

问题背景:

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

part1:解决方案

我在查阅资料时,有一本名叫《实战nginx》的书,作者张晏,这本书上有这么一段话“经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址”。这句话的意思是说,当你使用了nginx反向服务器后,在web端使用request.getRemoteAddr()(本质上就是获取$remote_addr),取得的是nginx的地址,即$remote_addr变量中封装的是nginx的地址,当然是没法获得用户的真实ip的,但是,nginx是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:

proxy_set_header            X-real-ip $remote_addr;

其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:

request.getAttribute("X-real-ip")

这样就明白了吧。

 

part2:原理介绍

这里我们将nginx里的相关变量解释一下,通常我们会看到有这样一些配置

server {

listen       88;

server_name  localhost;

#charset koi8-r;

#access_log  logs/host.access.log  main;

location /{

root   html;

index  index.html index.htm;

proxy_pass                  http://backend;

proxy_redirect              off;

proxy_set_header            Host $host;

proxy_set_header            X-real-ip $remote_addr;

proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;

# proxy_set_header            X-Forwarded-For $http_x_forwarded_for;

}

我们来一条条的看

1. proxy_set_header    X-real-ip $remote_addr;

这句话之前已经解释过,有了这句就可以在web服务器端获得用户的真实ip

但是,实际上要获得用户的真实ip,不是只有这一个方法,下面我们继续看。

2.  proxy_set_header            X-Forwarded-For $proxy_add_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;

意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。

那么$proxy_add_x_forwarded_for又是什么?

$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。

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

在第一台nginx中,使用

proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;

现在的$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。

到了第二台nginx,使用

proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;

现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”,这样就清楚了吧。

最后我们看到还有一个$http_x_forwarded_for变量,这个变量就是X-Forwarded-For,由于之前我们说了,默认的这个X-Forwarded-For是为空的,所以当我们直接使用proxy_set_header            X-Forwarded-For $http_x_forwarded_for时会发现,web服务器端使用request.getAttribute("X-Forwarded-For")获得的值是null。如果想要通过request.getAttribute("X-Forwarded-For")获得用户ip,就必须先使用proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;这样就可以获得用户真实ip。

使用Nginx后如何在web应用中获取用户ip及原理解释的更多相关文章

  1. Nginx 反向代理 如何在web应用中获取用户ip

    转载:http://blog.csdn.net/bao19901210/article/details/52537279 问题背景: 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断 ...

  2. 如何在Web.config中注册用户控件和自定义控件

    问题: 在ASP.NET 的早先版本里,开发人员通过在页面的顶部添加 指令来引入和使用自定义服务器控件和用户控件时,象这样: <%@ Register TagPrefix="scott ...

  3. 关于web请求中 获取真实IP

    HttpRequest request = HttpContext.Current.Request; if (!string.IsNullOrEmpty(request.ServerVariables ...

  4. Java Web应用中获取用户请求相关信息,如:IP地址、操作系统、浏览器等信息

    引入jar包 <dependency> <groupId>eu.bitwalker</groupId> <artifactId>UserAgentUti ...

  5. 采用CDN加速后,如何在程序里获取用户IP地址

    现在很多网站用了CDN技术,但采用CDN技术后,原来用来获取访问源的IP地址的程序已不能正常使用,它拿到的并不是访问源的真实IP地址,而是CDN节点的IP地址,解决方法是对获取IP的代码作一点小改动. ...

  6. [译]如何在Web开发中使用Python

    [译]如何在Web开发中使用Python 原文:HOWTO Use Python in the Web 摘要 这篇文档展示了Python如何融入到web中.它介绍了几种Python结合web服务器的方 ...

  7. Spring 如何在 WEB 应用中使用

    1. Spring 如何在 WEB 应用中使用 ? 1). 需要额外加入的 jar 包: spring-web-4.0.0.RELEASE.jar spring-webmvc-4.0.0.RELEAS ...

  8. go 通过nginx代理后获取用户ip

    go 如果使用自己的服务器,可以直接使用 net/http 来获取 func ip(w http.ResponseWriter, r *http.Request) { fmt.Println(r.Re ...

  9. web项目中获取spring的bean对象

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中不通过注解的形式(@Resource.@Autowired)获取Spring配置的bean呢? Bean工厂(c ...

随机推荐

  1. string转object-兼容低版本浏览器(eval实现)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. C#实现发送手机短信

  3. 一个队列类的实现(比delphi自带的速度快70倍)(线程安全版本)

    unit sfContnrs; interface {$DEFINE MULTI_THREAD_QUEUE} //线程安全版本,如果不需要线程安全,请注释掉此行代码 {$IFDEF MULTI_THR ...

  4. Android项目:使用pulltorefresh开源项目扩展为下拉刷新上拉加载更多的处理方法,监听listview滚动方向

    很多android应用的下拉刷新都是使用的pulltorefresh这个开源项目,但是它的扩展性在下拉刷新同时又上拉加载更多时会有一定的局限性.查了很多地方,发现这个开源项目并不能很好的同时支持下拉刷 ...

  5. nodejs 学习资料大全

    1.blog学习篇 http://blog.fens.me/series-nodejs/ 从零开始nodejs系列文章

  6. TCP粘包处理通用框架--C代码

    说明:该文紧接上篇博文“ linux epoll机制对TCP 客户端和服务端的监听C代码通用框架实现 ”讲来 (1)TCP粘包处理数据结构设计 #define MAX_MSG_LEN 65535 ty ...

  7. linux修改root管理员密码

    以root 身份登录(SSH操作) 输入 passwd 命令 就可以看到提示输入新密码了 输入密码的时候是看不到字符的.

  8. X264使用指南

    x264是一个开源的H.264视频编码器库.是目前最好的有损视频编码器. 基本用法是 x264 [options]-o outfile infile 主页: http://www.videolan.o ...

  9. userdel命令

    userdel 功能:删除用户相关文件:/etc/passwd    /etc/shadow    /home/usernameuserdel [-r] username 常用参数:-r    连同家 ...

  10. ASP.NET动态网站制作(23)-- ADO.NET(2)

    前言:这节课老师请高级班的E老师过来代课,还是接着老师讲的内容继续深入,修改了上节课老师写的部分代码. 内容: 1.数据库本质就是一个软件,这个软件帮助我们把数据有序地存储起来,当我们需要数据的时候帮 ...