关于代理:如何在Servlet中获取客户端的远程地址?

How do I get the remote address of a client in servlet?

有什么办法可以使客户机获得服务器的原始IP地址?
我可以使用request.getRemoteAddr(),但我似乎总是能获得代理服务器或Web服务器的IP。

我想知道客户端用来连接我的IP地址。 无论如何,我能得到吗?


尝试这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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(把它做成一个,但看起来像这样)


我用过的最好的解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
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;      
}

由于这通常是部署问题,而不是应用程序问题,因此另一种方法是适当地配置应用程序容器。配置完成后,容器将负责检查适当的标头,并且您的应用程序继续使用request.getRemoteAddr()

例如,在Tomcat中,您可以使用Remote IP Valve。我假设大多数应用程序服务器具有类似的功能。

容器还可以帮助您了解前端负载均衡器是否正在终止SSL连接,并通过HTTP将请求转发至应用服务器。当您的应用程序需要为其自身生成URL时,这一点很重要。


您无法以有意义的方式执行此操作。

代理可以添加也可以不添加代理标头,但是在许多情况下,无论如何这都是内部唯一的地址,因此对您而言毫无意义。无论如何,组织边缘的大多数代理都配置为尽可能少地揭示网络内部。

您打算将这些信息用于什么?


为什么不使用这样更优雅的解决方案?

1
2
3
4
5
6
7
8
9
10
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);
}

重复删除您的代码!


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

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

如果此标头不存在,那么我将按照@Bozho的建议进行操作


为什么我认为我们应该首先尝试从标头'X-Forwarded-For'获取IP?如果从request.getRemoteAddr()获取,则可能是客户端的真实IP或转发请求的上一个代理IP。因此,我们无法确定它属于哪个条件。但是,如果在标题中设置了" X-Forwarded-For",则客户端ip必定是从其获得的内容的最左侧部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    /**
     * 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"";
    }

1
2
3
4
5
6
7
String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null) {
            ipAddress = request.getHeader("X_FORWARDED_FOR");
            if (ipAddress == null){
                ipAddress = request.getRemoteAddr();
            }
        }

1
2
InetAddress inetAddress = InetAddress.getLocalHost();
String ip = inetAddress.getHostAddress();