JAVA服务器端获取客户端远程地址,根据IP获取远程地址,各IP地址查询接口比较

时间:2025-03-02 09:38:22

废话少说,先整代码:

一、根据远程请求,获取远程IP

/**
 * Copyright (c) 2016,sunnybs. 
 * All Rights Reserved.
 * 
 * Project Name:sunego-commerce-common
 * Package Name:
 * File Name:
 * Date:2016年4月28日 上午11:23:53
 * 
 */
package ;

import ;

/**
 * ClassName: IPUtils <br/>
 * Description: IP查询工具 <br/>
 * Date: 2016年4月28日 上午11:23:53 <br/>
 * <br/>
 * 
 * @author Administrator(邮箱)
 * 
 *         修改记录
 * @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>
 * 
 */

public class IPUtils {
    public static Address address;

    /**
     * 
     * getRemoteIP:获取远程请求客户端的外网IP <br/>
     * 
     * @param request
     *            请求实体对象
     * @return ip 外网ip<br/>
     */
    public static String getRemoteIP(HttpServletRequest request) {
        String ip = ("x-forwarded-for");
        if (ip == null || () == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = ("Proxy-Client-IP");
        }
        if (ip == null || () == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = ("WL-Proxy-Client-IP");
        }
        if (ip == null || () == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = ();
        }
        return ip;
    }

    /**
     * 
     * getAddresses:根据外网ip,判断该ip所在的地理位置 <br/>
     * 
     * @param ip
     *            外网ip
     * @return 该ip所在的地理位置 <br/>
     */
    public static String getAddresses(String ip) {
        return ().getAddresses(ip);
    }
}

二、根据远程IP,获取远程物理地址

/**
 * Copyright (c) 2016,sunnybs. 
 * All Rights Reserved.
 * 
 * Project Name:sunego-commerce-common
 * Package Name:
 * File Name:
 * Date:2016年4月28日 上午11:51:05
 * 
 */
package ;

import ;
import ;
import ;
import ;

import .;

import ;
import ;

/**
 * ClassName: Address <br/>
 * Description: TODO <br/>
 * Date: 2016年4月28日 上午11:51:05 <br/>
 * <br/>
 * 
 * @author Administrator(邮箱)
 * 
 *         修改记录
 * @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>
 * 
 */

public class Address {

    /** 多线程公共变量,key=ip,value=address */
    static final Map<String, String> ipAddressMap = new HashMap<String, String>();

    /** 线程池线程数 */
    static final Integer threadSize = 3;

    /** 太平洋ip地址查询接口 */
    static final String urlPcOnline = "/?ip={ip}&timeStamp={timeStamp}";
    /** 淘宝ip地址查询接口 */
    static final String urlTaobao = "/service/?ip={ip}&timeStamp={timeStamp}";
    /** 百度ip地址查询接口 */
    static final String urlBaidu = "/?resource_id=6006&format=json&query={ip}&timeStamp={timeStamp}";

    /**
     * 私有化构造方法
     */
    private Address() {
    };

    private static Address address;

    /**
     * 单例模式
     */
    public static Address getSingleInstance() {
        if (null == address) {
            // 懒加载
            synchronized () {
                if (null == address) {
                    address = new Address();
                }
            }
        }
        return address;
    }

    /**
     * 根据远程ip,查询对应的物理地址<br/>
     * 只返回所查询到的地址的最后一级,例如address="北京市海淀区西二旗",则返回"西二旗"<br/>
     * 使用太平洋、淘宝、百度三个ip地址查询接口,多进程异步查询<br/>
     */
    public String getAddresses(String ip) {
        // 清除上次查询结果
        (ip);
        // 创建一个可以执行三个线程的线程池
        ExecutorService pool = (threadSize);
        // 记录起始查询时间,超时未查到就返回空
        Long begin = ();
        // 设置时间戳,防止ip查询接口缓存数据
        String timeStamp = (begin);
        // 太平洋ip接口查询
        (new AddressPcOnline(ip, timeStamp));
        // 淘宝ip接口查询
        (new AddressTaobao(ip, timeStamp));
        // 百度ip接口查询
        (new AddressBaidu(ip, timeStamp));
        // 开始判断是否查询到结果
        while (null == (ip) && () - begin < 3000) {
            // 还未获得地址,且未超时(3秒),就等待(50毫秒)
            try {
                (50);
            } catch (InterruptedException e) {
                // 返回空
                return null;
            }
        }
        // 立即关闭所有进程
        ();
        // 返回查询到的结果
        return (ip);
    }

    public class AddressPcOnline implements Runnable {
        private String ip;
        private String timeStamp;
        String address;

        AddressPcOnline(String ip, String timeStamp) {
             = ip;
             = timeStamp;
        }

        @Override
        public void run() {
            try {
                String result = (("{ip}", ip).replace("{timeStamp}", timeStamp),
                        NHttpPool.CHARSET_GBK);
                result = (result);
                result = (34, () - 3);
                Map<?, ?> jsonResult = (result, );
                if (((ip))) {
                    return;
                }
                LogUtils.LOG_BIZ_INFO.info("urlPcOnline | ip=" + ip + " | result=" + result);
                address = (String) ("region");
                if ((address)) {
                    (ip, address);
                    return;
                }
                address = (String) ("city");
                if ((address)) {
                    (ip, address);
                    return;
                }
                address = (String) ("pro");
                (ip, address);
            } catch (Exception e) {
            }
        }
    }

    public class AddressTaobao implements Runnable {
        private String ip;
        private String timeStamp;
        String address;

        AddressTaobao(String ip, String timeStamp) {
             = ip;
             = timeStamp;
        }

        @Override
        public void run() {
            try {
                String result = (("{ip}", ip).replace("{timeStamp}", timeStamp),
                        NHttpPool.CHARSET_GBK);
                result = (17, () - 1);
                Map<?, ?> jsonResult = (result, );
                if (((ip))) {
                    return;
                }
                LogUtils.LOG_BIZ_INFO.info("urlTaobao | ip=" + ip + " | result=" + result);
                address = (String) ("county");
                if ((address)) {
                    (ip, address);
                    return;
                }
                address = (String) ("city");
                if ((address)) {
                    (ip, address);
                    return;
                }
                address = (String) ("region");
                (ip, address);
            } catch (Exception e) {
            }
        }
    }

    public class AddressBaidu implements Runnable {
        private String ip;
        private String timeStamp;
        String address;

        AddressBaidu(String ip, String timeStamp) {
             = ip;
             = timeStamp;
        }

        @Override
        public void run() {
            try {
                String result = (("{ip}", ip).replace("{timeStamp}", timeStamp),
                        NHttpPool.CHARSET_GBK);
                result = (49, () - 2);
                Map<?, ?> jsonResult = (result, );
                if (((ip))) {
                    return;
                }
                LogUtils.LOG_BIZ_INFO.info("urlBaidu | ip=" + ip + " | result=" + result);
                address = (String) ("location");
                if ((" ") > 0) {
                    address = (0, (" "));
                }
                if (("省") + 1 == ()) {
                    (ip, address);
                    return;
                }
                if (("市") + 1 == ()) {
                    address = (("省") + 1);
                    (ip, address);
                    return;
                }
                address = (("市") + 1, ());
                (ip, address);
            } catch (Exception e) {
            }
        }
    }
}


三、测试用例

/**
 * Copyright (c) 2016,sunnybs. 
 * All Rights Reserved.
 * 
 * Project Name:sunego-commerce-common
 * Package Name:
 * File Name:
 * Date:2016年2月20日 下午2:55:35
 * 
 */
package ;

import ;
import ;

import ;

import ;

/**
 * ClassName: PriceUtilsTest <br/>
 * Description: TODO <br/>
 * Date: 2016年2月20日 下午2:55:35 <br/>
 * <br/>
 * 
 * @author WSP(邮箱)
 * 
 *         修改记录
 * @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>
 * 
 */

public class IPUtilsTest {
    @Test
    public void testIPUtils() {
        /**
         * 以下接口不可用 <br>
         * "/api/ip/";<br>
         * "/ipaddress";<br>
         * "/cityjson";// 仅支持js,不接受ip参数<br>
         * "/app/";<br>
         * "/smartresult-xml/";<br>
         * "./ipquery";// 仅支持js<br>
         * "http://app./ipquery/?rtype=2";<br>
         * "http://w./chaxun/?ip=";// 太慢<br>
         */
        List<String> ipList = new ArrayList<String>();
        ("219.137.144.0");// 广东省广州市海珠区
        ("1.85.35.131");// 陕西省西安市 电信
        ("59.108.111.0");// 北京市北京市 方正宽带
        ("59.104.167.0");// *省
        ("61.186.76.165");// 湖南省怀化市 电信
        ("221.202.127.39");// 辽宁省葫芦岛市 联通
        ("114.252.45.210");// 北京市北京市 联通
        ("127.0.0.1");// 未分配或者内网
        ("192.168.10.170");// 未分配或者内网
        ("132.191.25.116:8080");// 辽宁省葫芦岛市

        for (int i = 0; i < (); i++) {
            String ip = (i);
            String addresses = (ip);
            (ip + "==" + addresses);
        }
        ("\r\n\r\n***************************\r\n\r\n睡5秒\r\n\r\n***************************\r\n\r\n");
        try {
            (5000);
        } catch (InterruptedException e) {
            ();
        }
        for (int j = 63; j < 266; j += 63) {
            for (int k = 0; k < 266; k += 19) {
                for (int m = 0; m < 266; m += 13) {
                    String ip = "60." + j + "." + k + "." + m;
                    String address1 = (ip);
                    (ip + "==" + address1);
                }
            }
        }
    }

}

代码整完了,问题也解决了……

说明一下,

我最开始获取客户端地址,用的是在前端页面引入“./ipquery”接口,

但此接口只支持js,无法写到Java后台去,

项目从http转https后该接口边便失效,又找不到https协议的ip查询接口,

因此只能在后台获取远程ip(LSB的话记得ip转换),便开始在后台使用淘宝的ip地址查询接口,

可是高频率访问时淘宝ip地址查询接口总是SocketTimeout,经过各种Httpclient优化无效,后来发现加上时间戳去缓存可以改善连接超时,

就这样用了一段时间后,频繁访问时还是会报SocketTimeoutException,

因此又调研了这许多接口,最终确定了三个比较高效、精确、稳定的接口,做成了多线程的方式随机访问。