有什么办法可以让客户端的原始IP地址进入服务器?我可以使用 request.getRemoteAddr()
,但我似乎总是获得代理或网络服务器的 IP。
我想知道客户端用来连接我的 IP 地址。无论如何我可以得到它吗?
尝试这个:
public static String getClientIpAddr(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.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.getRemoteAddr();
}
return ip;
}
request.getRemoteAddr()
是方法。看来您的代理更改了源 IP。当一些代理这样做时,他们会在一些自定义 http 标头中添加原始 IP。使用 request.getHeaderNames()
和 request.getHeaders(name)
并打印所有这些以查看是否没有任何感兴趣的内容。像X-CLIENT-IP
(做了一个,但它们看起来像这样)
为什么不使用这样更优雅的解决方案?
private static final List<String> IP_HEADERS = Arrays.asList("X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR");
public static String getClientIpAddr(HttpServletRequest request) {
return IP_HEADERS.stream()
.map(request::getHeader)
.filter(Objects::nonNull)
.filter(ip -> !ip.isEmpty() && !ip.equalsIgnoreCase("unknown"))
.findFirst()
.orElseGet(request::getRemoteAddr);
}
对您的代码进行重复数据删除!
由于这通常是部署问题,而不是应用程序问题,因此另一种方法是适当地配置应用程序容器。配置完成后,容器会负责检查相应的标头,并且您的应用程序会继续使用 request.getRemoteAddr()
。
例如,在 Tomcat 中,您可以使用 Remote IP Valve。我会假设大多数应用程序服务器都具有类似的功能。
该容器还可以负责了解您的前端负载均衡器是否正在终止 SSL 连接,并通过 HTTP 将请求转发到应用服务器。当您的应用程序需要为其自身生成 URL 时,这一点很重要。
我用过的最好的解决方案
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。但我认为并非所有代理/磅都添加此标头。
这里有一些用于解析标头的 java 代码:http://www.codereye.com/2010/01/get-real-ip-from-request-in-java.html
如果此标头不存在,那么我将按照@Bozho 的建议进行
String ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null) {
ipAddress = request.getHeader("X_FORWARDED_FOR");
if (ipAddress == null){
ipAddress = request.getRemoteAddr();
}
}
为什么我认为我们应该首先尝试从标头“X-Forwarded-For
”获取 IP?如果您从 request.getRemoteAddr()
获得,它可能是 client's real ip or last proxy's ip which forwards the request。因此我们无法判断它属于哪个条件。但是,如果将 'X-Forwarded-For
' 设置到标头中,则客户端 ip 必然是您从中获得的最左边的部分。
/**
* Try to get real ip from request:
* <ul>
* <li>try X-Forwarded-For</li>
* <li>try remote address</li>
* </ul>
*
* @param request request
* @return real ip or ""
*/
private String tryGetRealIp(HttpServletRequest request) {
// X-Forwarded-For: <client>, <proxy1>, <proxy2>
// If a request goes through multiple proxies, the IP addresses of each successive proxy is listed.
// This means, the right-most IP address is the IP address of the most recent proxy and
// the left-most IP address is the IP address of the originating client.
String forwards = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotBlank(forwards)) {
// The left-most IP must be client ip
String ip = StringUtils.substringBefore(forwards, ",");
return ip;
} else if (StringUtils.isNotBlank(request.getRemoteAddr())) {
// this could be real client ip or last proxy ip which forwards the request
return request.getRemoteAddr();
}
return "";
}
request.getHeader("True-Client-IP")
它将返回客户端 IP 地址
InetAddress inetAddress = InetAddress.getLocalHost();
String ip = inetAddress.getHostAddress();