Utils:获取请求客户端的真实IP地址

star2017 1年前 ⋅ 625 阅读

获取真实 IP 地址。一次项目中有记录请求方的 IP,某天收集到的 IP 地址全是相同的,后面定位到问题是在阿里云启用了 SLB(负载均衡),收集到的全是负载均衡服务器的 IP,而不是用户端的 IP,后面改为判断从 x-forwarded-for 中取。

真实IP

  1. 获取真实 IP 地址

    package utils;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.StringTokenizer;
    import java.util.regex.Pattern;
    
    public class IPUtil {
    
        public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
        public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");
    
        /**
         * 获取IP地址普通方式
         *
         * @param request
         * @return
         */
        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;
        }
    
        public static String longToIpV4(long longIp) {
            int octet3 = (int) ((longIp >> 24) % 256);
            int octet2 = (int) ((longIp >> 16) % 256);
            int octet1 = (int) ((longIp >> 8) % 256);
            int octet0 = (int) ((longIp) % 256);
            return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
        }
    
        public static long ipV4ToLong(String ip) {
            String[] octets = ip.split("\\.");
            return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16)
                    + (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
        }
    
        public static boolean isIPv4Private(String ip) {
            long longIp = ipV4ToLong(ip);
            return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255"))
                    || (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255"))
                    || longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
        }
    
        public static boolean isIPv4Valid(String ip) {
            return pattern.matcher(ip).matches();
        }
    
        /**
         * 更完善的获取IP地址
         * @param request
         * @return
         */
        public static String getIpFromRequest(HttpServletRequest request) {
            String ip;
            boolean found = false;
            if ((ip = request.getHeader("x-forwarded-for")) != null) {
                StringTokenizer tokenizer = new StringTokenizer(ip, ",");
                while (tokenizer.hasMoreTokens()) {
                    ip = tokenizer.nextToken().trim();
                    if (isIPv4Valid(ip) && !isIPv4Private(ip)) {
                        found = true;
                        break;
                    }
                }
            }
            if (!found) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }
    }
    
  2. 从请求头中获取IP 地址,IP地址是可被改变的。

    $.ajax({
        type : "GET",
        headers : {"X-Forwarded-For":randomIp,"WL-Proxy-Client-IP":randomIp},
        contentType : 'application/x-www-form-urlencoded;charset=utf-8',
        url : url,
        data:params,
        dataType : "text",
        success : function(data) {
            count++;
            console.log("时间:【"+new Date()+"】 执行成功:【"+count+"】次:"+data);
        if(max>0){
            setTimeout(function wait(){
                console.log("等待"+(timeWait)+"ms ...");
                vote(max,getRandomNum(maxWait,minWait));
            },timeWait);
        }
        }
    
    }
    
  3. Nginx 反向代理设置头信息中的远程IP地址

    Nginx 反身代理设置,将 X-Forward-For 替换为 remote_addr

    #Nginx 设置
    location  ~  ^/static {
    proxy_pass  ....;
    proxy_set_header X-Forward-For $remote_addr ;
    }
    
  4. 另一种方式获取IP

    public class IPUtil {
    
        public static String getIPAddress(HttpServletRequest request) {
            String ip = null;
    
            //X-Forwarded-For:Squid 服务代理
            String ipAddresses = request.getHeader("X-Forwarded-For");
    
            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
                //Proxy-Client-IP:apache 服务代理
                ipAddresses = request.getHeader("Proxy-Client-IP");
            }
    
            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
                //WL-Proxy-Client-IP:weblogic 服务代理
                ipAddresses = request.getHeader("WL-Proxy-Client-IP");
            }
    
            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
                //HTTP_CLIENT_IP:有些代理服务器
                ipAddresses = request.getHeader("HTTP_CLIENT_IP");
            }
    
            if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
                //X-Real-IP:nginx服务代理
                ipAddresses = request.getHeader("X-Real-IP");
            }
    
            //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
            if (ipAddresses != null && ipAddresses.length() != 0) {
                ip = ipAddresses.split(",")[0];
            }
    
            //还是不能获取到,最后再通过request.getRemoteAddr();获取
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }
    }
    

参考资料

  1. 正确获取真实的 IP地址
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: