转自:blog.csdn.net/youanyyou/a…nginx
在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分状况下都是有效的。可是在经过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。web
若是使用了反向代理软件,将http://192.168.1.110:2046/的URL反向代理为www.abc.com/的URL时,用request.getRemoteAddr()方法获取的IP地址是:127.0.0.1或192.168.1.110,而并非客户端的真实IP。apache
通过代理之后,因为在客户端和服务之间增长了中间层,所以服务器没法直接拿到客户端的IP,服务器端应用也没法直接经过转发请求的地址返回给客户端。可是在转发请求的HTTP头信息中,增长了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。浏览器
当咱们访问www.abc.com/index.jsp/时,其实并非咱们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问http://192.168.1.110:2046/index.jsp,代理服务器再将访问到的结果返回给咱们的浏览器,由于是代理服务器去访问index.jsp的,因此index.jsp中经过request.getRemoteAddr()的方法获取的IP其实是代理服务器的地址,并非客户端的IP地址。bash
先说说这些请求头的意思服务器
这是一个 Squid 开发的字段,只有在经过了HTTP代理或者负载均衡服务器时才会添加该项。网络
格式为X-Forwarded-For:client1,proxy1,proxy2,通常状况下,第一个ip为客户端真实ip,后面的为通过的代理服务器ip。如今大部分的代理都会加上这个请求头。架构
这个通常是通过apache http服务器的请求才会有,用apache http作代理时通常会加上Proxy-Client-IP请求头,而WL-Proxy-Client-IP是他的weblogic插件加上的头。负载均衡
有些代理服务器会加上此请求头。jsp
下面是一个参考获取客户端IP地址的方法:
public static String getIpAddress(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();
}
if (ip.contains(",")) {
return ip.split(",")[0];
} else {
return ip;
}
}1234567891011121314151617复制代码
若是使用的是Druid链接池,能够参考使用:com.alibaba.druid.util.DruidWebUtils#getRemoteAddr方法,但这个是通过多级代理的IP地址,须要本身处理下获取第一个。
有几点要注意
这些请求头都不是http协议里的标准请求头,也就是说这个是各个代理服务器本身规定的表示客户端地址的请求头。若是哪天有一个代理服务器软件用oooo-client-ip这个请求头表明客户端请求,那上面的代码就不行了。
这些请求头不是代理服务器必定会带上的,网络上的不少匿名代理就没有这些请求头,因此获取到的客户端ip不必定是真实的客户端ip。代理服务器通常均可以自定义请求头设置。
即便请求通过的代理都会按本身的规范附上代理请求头,上面的代码也不能确保得到的必定是客户端ip。不一样的网络架构,判断请求头的顺序是不同的。
最重要的一点,请求头都是能够伪造的。若是一些对客户端校验较严格的应用(好比投票)要获取客户端ip,应该直接使用ip=request.getRemoteAddr(),虽然获取到的多是代理的ip而不是客户端的ip,但这个获取到的ip基本上是不可能伪造的,也就杜绝了刷票的可能。(有分析说arp欺骗+syn有可能伪造此ip,若是真的能够,这是全部基于TCP协议都存在的漏洞),这个ip是tcp链接里的ip