如何在servlet中获取客户端的远程地址?

77

有没有办法获取连接到服务器的客户端的原始IP地址?

我可以使用request.getRemoteAddr(),但我似乎总是得到代理或Web服务器的IP。

我想知道客户端用于连接到我的IP地址。有什么方法可以获取它吗?

12个回答

120

试试这个:

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;  
    }  

在这种情况下,使用if条件语句而不是if/else是否可以? - Andry
1
是的,因为我们需要检查前一个操作是否成功,也许使用do-while会更好。 - Fareed Alnamrouti
4
X-Forwarded-For 可以包含多个 IP 地址。 - dmatej

11

为何不使用更加优雅的解决方案,例如这种方式?

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);
}

代码去重!


10

request.getRemoteAddr() 是正确的方法。看起来您的代理更改了源IP。当一些代理这样做时,它们会在某个自定义HTTP头中添加原始IP。使用 request.getHeaderNames()request.getHeaders(name) 并将所有内容打印出来,以查看是否有任何值得关注的内容,例如 X-CLIENT-IP(我编的这一个,但它们看起来像这样)。


谢谢,我会检查头文件……不过当它通过一个Web服务器时,比如说,我就会得到Web服务器的地址。 - grassbl8d
2
你是指request.getHeaderNames()吗? - theyuv

7
由于这通常是部署问题而不是应用程序问题,另一种方法是适当地配置应用程序容器。 配置完成后,容器会负责检查适当的头信息,您的应用程序仍然使用request.getRemoteAddr()
例如,在Tomcat中,您可以使用远程IP阀门。 我认为大多数应用程序服务器都具有类似的功能。
容器还可以负责了解您的前端负载均衡器是否终止了SSL连接,并将请求通过HTTP转发到应用程序服务器。 当您的应用程序需要生成指向自身的URL时,这非常重要。

6
我曾使用过的最佳解决方案
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;      
} 

4

你不能以有意义的方式这样做。

代理服务器可能会添加代理头信息,但在许多情况下,这仍然是一个内部地址,对你来说是没有意义的。大多数在组织边缘的代理都配置为尽可能少地揭示网络内部的信息。

你打算用这些信息做什么?


好的,我需要记录访问者的地址。你说得对,有些代理似乎会删除它,而且我经常被代理替换掉... 我在想,也许我可以从SSL会话中获取一些信息。 - grassbl8d
不行。客户端IP在SSL协商中没有传递。 - Stephen C

1
"

如果使用代理或负载均衡器,“x-forwarded-for”请求头包含原始客户端IP。但我认为并非所有代理/负载均衡器都添加了此标头。

以下是一些Java代码以解析标头: http://www.codereye.com/2010/01/get-real-ip-from-request-in-java.html

如果不存在此标头,则应按照@Bozho的建议进行处理。

"

0
String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null) {
            ipAddress = request.getHeader("X_FORWARDED_FOR");
            if (ipAddress == null){
                ipAddress = request.getRemoteAddr();
            }
        }

0

为什么我认为我们应该首先从头部 'X-Forwarded-For' 获取IP?如果你从 request.getRemoteAddr() 获取,它可能是客户端真实IP或转发请求的最后一个代理的IP。因此,我们无法确定它属于哪种情况。然而,如果 '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 "";
    }

0

request.getHeader("True-Client-IP")

它将返回客户端的IP地址


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接