- 在开发工作中,我们常常需要获取客户端的ip。一般获取客户端ip的方法是request.getRemoteAddr(),但是在通过了Apache、squid等反向代理软件后,这样不能获取到客户端的真实ip地址了。
- 如果使用了反向代理软件,将http://192.168.1.110.2046的url反向代理为http://www.abc.com/,当我们访问http://www.abc.com/index.jsp时,其实浏览器并不是真正访问到了服务器上的index.jsp文件,而是先由反向代理服务器去访问http://192.168.1.110:2046/index.jsp,反向代理服务器再将访问到的结果返回给浏览器。由于是反向代理服务器去访问index.jsp的,所以index.jsp中通过request.getRemoteAddr()的方法获取到的实际上是反向代理服务器的地址,并不是客户端的地址。
- 图示为不通过代理上网(其中resin服务器为一种web服务器)
- 这种通过remoteip可以直接获取
- 下面是通过代理上网的图例(其中代理服务器也可以是nginx)
- 其中X-Forwarded-For和X-Real-IP都不是http的正式协议头,而是squid等反向代理软件最早引入的。如果连XFF第一个都不是客户ip,那么第二个就更不靠谱了。XFF就会按照代理链将一系列的ip地址存储起来。
- 由图可得,在程序服务器中拿最原始的ip逻辑:
- 如果XFF不为空,拿第一个
- 为空,拿XRI
- 如果XRI为空,拿remoteAddr,即只能拿最直接发给他的机器的ip
代码
public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(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(); if(ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")){ //根据网卡取本机配置的IP InetAddress inet=null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ip= inet.getHostAddress(); } } return ip; }
- 参考文章
- 参考文章
- 代码示例:D:/dieaprojects/thz/thz-parent/thz-common/IPUtil