Nginx反向代理后,web服务器获取真实访问IP的方法

场景描述

使用Nginx反向代理后,获取用户的ip地址时,获取到的是服务器本身的ip地址,而非用户真实的ip地址。

在Servlet里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid,Nginx等反向代理软件就不能获取到客户端的真实IP地址了。


问题分析

如果使用了反向代理软件,例如将http://192.168.101.88:80/ 的URL反向代理为http://www.javaex.cn/ 的URL时,用request.getRemoteAddr()方法获取的IP地址是:127.0.0.1 或 192.168.101.88(服务器本身的ip地址),而并不是客户端的真实IP地址。

如下图,

原来是client端直接请求服务端,走A路线请求,这时候通过request.getRemoteAddr()方法可以准备的获取客户端的IP。

但是做了代理之后呢,client端不是直接请求服务端,而是走B线路请求代理服务器,由代理器去请求服务端,这时候服务端通过request.getRemoteAddr()方法拿到的理所当然是代理服务器的地址了。



解决方法

Nginx做如下配置

proxy_set_header    Host             $host;		#保留代理之前的host
proxy_set_header X-Real-IP $remote_addr; #保留代理之前的真实客户端ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header HTTP_X_FORWARDED_FOR $remote_addr; #在多级代理的情况下,记录每次代理之前的客户端真实ip
proxy_redirect default; #指定修改被代理服务器返回的响应头中的location头域跟refresh头域数值



Java后台获取ip地址工具类

/**
* 获取来源ip地址
* @param request
* @return
*/
public static String getIp(HttpServletRequest request) {
if (request==null) {
return "unknown";
}

String ip = null;

// X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");

if (ipAddresses==null || ipAddresses.length()==0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ipAddresses = request.getHeader("Proxy-Client-IP"); // Proxy-Client-IP:apache 服务代理
}
if (ipAddresses==null || ipAddresses.length()==0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ipAddresses = request.getHeader("WL-Proxy-Client-IP"); // WL-Proxy-Client-IP:weblogic 服务代理
}
if (ipAddresses==null || ipAddresses.length()==0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ipAddresses = request.getHeader("HTTP_CLIENT_IP"); // HTTP_CLIENT_IP:有些代理服务器
}
if (ipAddresses==null || ipAddresses.length()==0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ipAddresses = request.getHeader("X-Real-IP"); // X-Real-IP:nginx服务代理
}

// 有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses!=null && ipAddresses.length()!=0) {
ip = ipAddresses.split(",")[0];
}

// 还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}

return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}