Java获取客户端IP

来源:互联网 发布:js 获取复选框选中的值 编辑:程序博客网 时间:2024/05/29 18:10

在开发工作中,我们常常需要获取客户端的IP。一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

原因:由于在客户端和服务之间增加了中间代理,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。

现在图示代理上网和IP的关系:

 

第一种情况:不通过代理上网,服务器端拿到真实IP

 

第二种情况:通过代理服务器如:Nginx,Squid等一层代理或多层代理上网,如下图:

 

需要注意的是X-Forwarded-For和X-Real-IP都不是http的正式协议头,而是squid等反向代理软件最早引入的,之所以resin能拿到,是因为NGINX里一般缺省都会这么配置转发的http请求:

location / {

         proxy_pass       http://yourdomain.com;

         proxy_set_header   Host             $host;

         proxy_set_header   X-Real-IP        $remote_addr;

         proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

         },从X-Forwarded-For的定义来看,ips[0]才是原始客户端ip,如果这个都不是,那拿第二个就更不靠谱了,我们平时检验的时候,可能是直接在内网挂代理去访问的,跟外面网友访问经过的网络路径不一样,后面不停添加的是经过的每一层代理ip才对,下面举例说明;

request.getRemoteAddr() 192.168.239.196

request.getHeader("X-Forwarded-For") 58.63.227.162, 192.168.237.178, 192.168.238.218

request.getHeader("X-Real-IP") 192.168.238.218

所以访问的流程应该是这样,客户端58.63.227.162发出请求,经过192.168.237.178, 192.168.238.218两层转发,到了192.168.239.196这台NGINX上,NGINX就把X-Real-IP头设成了自己看到的remote_addr,也就是直接发给到他的192.168.238.218,这时候resin收到这个包,对resin来说直接发给他的remote_addr就是NGINX的ip,也就是192.168.239.196,那么resin里面的request.getRemoteAddr()就是192.168.239.196,那么在resin里拿最原始的ip逻辑(也就是拿能够知道的最外层的ip)应该是这样:

            如果XFF不为空,拿XFF的左边第一个

            如果XFF为空,拿XRI

            如果XRI为空,只能拿request.getRemoteAddr(),也就是只能拿到最直接发给他的机器ip了,

其他都不可考究,参考代码如下:

第一种代码:

复制代码
      /**      * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip      * @param request      * @return ip      */    public static String getLocalIp(HttpServletRequest request) {        String remoteAddr = request.getRemoteAddr();        String forwarded = request.getHeader("X-Forwarded-For");        String realIp = request.getHeader("X-Real-IP");        String ip = null;        if (realIp == null) {            if (forwarded == null) {                ip = remoteAddr;            } else {                ip = remoteAddr + "/" + forwarded.split(",")[0];            }        } else {            if (realIp.equals(forwarded)) {                ip = realIp;            } else {                if(forwarded != null){                    forwarded = forwarded.split(",")[0];                }                ip = realIp + "/" + forwarded;            }        }        return ip;    }
复制代码

第二种代码:

复制代码
 1      public static String getIp(HttpServletRequest request) { 2         String remoteAddr = request.getRemoteAddr(); 3         String forwarded = request.getHeader("X-Forwarded-For"); 4         String realIp = request.getHeader("X-Real-IP"); 5  6         String ip = null; 7         if (realIp == null) { 8             if (forwarded == null) { 9                 ip = remoteAddr;10             } else {11                 ip = remoteAddr + "/" + forwarded;12             }13         } else {14             if (realIp.equals(forwarded)) {15                 ip = realIp;16             } else {17                 ip = realIp + "/" + forwarded.replaceAll(", " + realIp, "");18             }19         }20         return ip;21     }
复制代码

第三种代码:

复制代码
 1        public static String getIp2(HttpServletRequest request) { 2            String ip = request.getHeader("X-Forwarded-For"); 3            if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ 4                //多次反向代理后会有多个ip值,第一个ip才是真实ip 5                int index = ip.indexOf(","); 6                if(index != -1){ 7                    return ip.substring(0,index); 8                }else{ 9                    return ip;10                }11            }12            ip = request.getHeader("X-Real-IP");13            if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){14                return ip;15            }16            return request.getRemoteAddr();17        }
第三种是最合适的,最清晰理解的
复制代码整理网友的材料,最后有源码,亲测能解决所有java获取IP真实地址的问题

整理的这里:

1、链接1 

2、链接2

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

如果使用了反向代理软件,将
http://192.168.1.110:2046/
的URL反向代理为
http://www.javapeixun.com.cn /
的URL时,用
request.getRemoteAddr()
方法获取的IP地址是:127.0.0.1 或 192.168.1.110,而并不是客户端的真实IP。

ISAPI过滤器也会对request对象进行再包装,附加一些WLS要用的头信息。实际的iisforward附加头如下:

[code]WL-Proxy-Client-IP=211.161.1.239  Proxy-Client-IP=211.161.1.239  X-Forwarded-For=211.161.1.239  WL-Proxy-Client-Keysize=   WL-Proxy-Client-Secretkeysize=   X-WebLogic-Request-ClusterInfo=true  X-WebLogic-KeepAliveSecs=30  X-WebLogic-Force-JVMID=-327089098  WL-Proxy-SSL=false


经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。当我们访问
http://www.javapeixun.com.cn /index.jsp/
时,其实并不是我们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问
http://192.168.1.110:2046/index.jsp
,代理服务器再将访问到的结果返回给我们的浏览器,因为是代理服务器去访问index.jsp的,所以index.jsp中通过
request.getRemoteAddr()
的方法获取的IP实际上是代理服务器的地址,并不是客户端的IP地址。

于是可得出获得客户端真实IP地址的方法一:

[code]public String getRemortIP(HttpServletRequest request) {   if (request.getHeader("x-forwarded-for") == null) {    return request.getRemoteAddr();   }   return request.getHeader("x-forwarded-for");  }


可是当我访
问http://www.5a520.cn /index.jsp/
时,返回的IP地址始终是unknown,也并不是如上所示的127.0.0.1 或 192.168.1.110了,而我访问
http://192.168.1.110:2046/index.jsp
时,则能返回客户端的真实IP地址,写了个方法去验证。原因出在了Squid上。squid.conf 的配制文件 forwarded_for 项默认是为on,如果 forwarded_for 设成了 off  则:
X-Forwarded-For: unknown


于是可得出获得客户端真实IP地址的方法二:

[code]public String getIpAddr(HttpServletRequest request) {        String ip = request.getHeader("x-forwarded-for");        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {            ip = request.getHeader("Proxy-Client-IP");        }        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {            ip = request.getHeader("WL-Proxy-Client-IP");        }        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {            ip = request.getRemoteAddr();        }        return ip;    }


可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?

答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。

如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100用户真实IP为: 192.168.1.110

以上方法还不行的话就采用如下方法:

[code]/**      * 获取当前网络ip      * @param request      * @return      */      public String getIpAddr(HttpServletRequest request){          String ipAddress = request.getHeader("x-forwarded-for");              if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {                  ipAddress = request.getHeader("Proxy-Client-IP");              }              if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {                  ipAddress = request.getHeader("WL-Proxy-Client-IP");              }              if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {                  ipAddress = request.getRemoteAddr();                  if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){                      //根据网卡取本机配置的IP                      InetAddress inet=null;                      try {                          inet = InetAddress.getLocalHost();                      } catch (UnknownHostException e) {                          e.printStackTrace();                      }                      ipAddress= inet.getHostAddress();                  }              }              //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割              if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15                  if(ipAddress.indexOf(",")>0){                      ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));                  }              }              return ipAddress;       }

 

/** * 获取当前客户端IP地址 * @param request * @return */public static String getRemoteAddress(HttpServletRequest request){    String ip = request.getHeader("x-forwarded-for");         if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {              // 多次反向代理后会有多个ip值,第一个ip才是真实ip            if( ip.indexOf(",")!=-1 ){                ip = ip.split(",")[0];            }        }          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {              ip = request.getHeader("Proxy-Client-IP");          }          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {              ip = request.getHeader("WL-Proxy-Client-IP");          }          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {              ip = request.getHeader("HTTP_CLIENT_IP");          }          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {              ip = request.getHeader("HTTP_X_FORWARDED_FOR");          }          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {              ip = request.getHeader("X-Real-IP");          }          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {              ip = request.getRemoteAddr();          }         return ip;}