Java-IP获取测试

测试代码

    @RequestMapping("/hello1")
    public Map getIp1(HttpServletRequest request) {

        Enumeration names = request.getHeaderNames();
        ArrayList array = new ArrayList();
        while (names.hasMoreElements()){
            array.add(names.nextElement());
        }

        Map map = new HashMap<>();
        for (int i = 0; i < array.size(); i++) {
            String key = array.get(i);
            map.put(key, request.getHeader(key));
        }

        map.put("侯万getRemoteAddr", request.getRemoteAddr());

        String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = inet.getHostAddress();
            }
        }
        
        // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        map.put("ipAddress", ipAddress);
        return map;
    }

资料1:

如果服务器使用了Nginx代理,需要设置Nginx的配置,才能获取到IP,因为经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,只能通过$remote_addr变量拿到的将是反向代理服务器的ip地址。
我在default.conf的配置是:

server {
    listen 443 ssl;  # 支持ipv4
    listen [:]:443 ssl;  # 支持ipv6
    
    location /hello {
        proxy_pass http://182.92.106.69:8848/hello1/;
        proxy_redirect    off;

        # 关键的四句代码
        proxy_set_header  Host             $host:$server_port;
        proxy_set_header  X-Real-IP        $remote_addr;
        proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto $scheme;
    }
}

Nginx中的几个变量解释:

  • $remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,icanhazip的原理也是这样, 当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器就会把remote_addr设为你在公网暴露的IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP, 除非代理将你的IP附在请求header中一起转交给web服务器。
  • $proxy_add_x_forwarded_for 全局变量$proxy_add_x_forwarded_for包含客户端请求头中的X-Forwarded-For,与$remote_addr两部分,他们之间用逗号分开。X-Forwarded-For(简称XFF),X-Forwarded-For 是一个 HTTP 扩展头部。RFC 2616 协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension` 标准之中。
  • $proxy_set_header,可设置代理后 header
  • X-Real-IP 一般比如X-Real-IP这一个自定义头部字段,通常被 HTTP 代理用来表示与它产生TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端,这个要看经过代理的层级次数或是是否始终将真实IP一路传下来。(牢记:任何客户端传上来的东西都是不可信的)

当多层代理或使用CDN时,如果代理服务器不把用户的真实IP传递下去,那么服务器将永远不可能获取到用户的真实IP。

资料2:

上面存在问题是,可能一个基站,或者一个小区,对外只有一个公共IP。因此这种情况下,同一ip出现数百用户也是正常的。
典型的是:一个公司内,大家共同用同一个网络,对外都是一个的公网IP。

资料3:

私有的内部组网IP段(可作为代码直接判断):

  • A类:10.0.0.0 — 10.255.255.255 10.0.0.0/8
  • B类:172.16.0.0 — 172.31.255.255 172.16.0.0/12
  • C类:192.168.0.0 — 192.168.255.255 192.168.0.0/16

资料4:

参考文档:

  • 后端nginx使用set_real_ip_from获取用户真实IP

你可能感兴趣的:(Java-IP获取测试)