最近将项目放到公网,结果反复刷新页面后,出现了大量的[ERROR] session ip change too many (WebSessionStat.java:266)错误,如下图
仔细查找,原来是alibaba druid提示的,具体来说,是druid监控session时,记录访问IP提示的。
如果只想看解决方法,对原因无兴趣,请直接跳到本文末尾,下面是产生的原因。
首先打开druid的源代码,找到com.alibaba.druid.support.http.stat.WebSessionStat类,可以看到输出错误的源代码
public void addRemoteAddress(String ip) {
if (remoteAddresses == null) {
this.remoteAddresses = ip;
return;
}
if (remoteAddresses.contains(ip)) {
return;
}
if (remoteAddresses.length() > 256) {
LOG.error("session ip change too many");
return;
}
remoteAddresses += ';' + ip;
}
很明显,是由于每次访问的ip不一样,然后remoteAddresses += ';' + ip;多次累加,导致remoteAddresses超过了256位长度。可是为什么同一个session每次ip会不一样,ip又是怎么获取的,这需要继续跟踪源代码。
跟踪源代码可以看到com.alibaba.druid.util.DruidWebUtils的public static String getRemoteAddr(HttpServletRequest request)方法中,是这么获取IP的:
public static String getRemoteAddr(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;
}
可以看到,druid获得ip的方法是request.getHeader("x-forwarded-for");,这个方法会获取到ip:port,而国内由于公网IP极其匮乏,导致绝大部分人上网都是通过地址映射以后来上网,这就导致了每次请求的ip、端口都可能不一样,那么自然会被WebSessionStat.addRemoteAddress()方法累加到remoteAddresses,导致remoteAddresses越来越长,最终超过256位长度,触发LOG.error("session ip change too many");语句。
知道原因,下面就是修改方法:
方法一:关闭druid的session监控。
在web.xml配置druid的地方,将sessionStatEnable设为false即可,如下:
方法二:修改druid的源码。
下载或反编译druid的源码,将LOG.error("session ip change too many");注释掉,或者将if条件长度改大即可。
方法三:等。等阿里巴巴官方修改相关代码。
参考文献:http://www.oschina.net/question/579092_243246