问题描述
需要获取真实的请求IP,但是由于有Nginx、网关等转发,如果使用HttpServletRequest实例的getRemoteAddr()方法,不会得到真实的请求IP。
解决方法
使用Nginx、Apache、Squid等进行HTTP代理或者负载均衡时,会在请求头中添加X-Forwarded-For字段(戳我get新知识),如果有多个转发,那么最后值为如下格式:
X-Forwarded-For: client1,proxy1,proxy2,proxy3
注意: 配置Nginx代理时,必须要配置以下内容:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
此配置意为将当前代理的IP 追加 到 X-Forwarded-For 字段中。
此时,第一个值即为真实的IP地址,我们通过代码取出它即可:
public String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0];
} else {
ip = request.getRemoteAddr();
}
return ip;
}
当然,针对不同的代理,加的请求头字段也可能会不同,那么就可以用以下的代码:
public String getIpAddress(HttpServletRequest request) throws UnknownHostException {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
// apache 代理添加的请求头
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
// weblogic 代理添加的请求头
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
// 某些代理服务器的请求头
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
// 某些代理服务器的请求头
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
//根据网卡取本机配置的IP
InetAddress inet = InetAddress.getLocalHost();
ip = inet.getHostAddress();
}
}
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
return ip;
}