官方服务微信:dat818 购买与出租对接

IP 地址定位:接入方式、问题及新发现的 Ip2region 项目

3万

主题

2

回帖

11万

积分

管理员

积分
115352
发表于 昨天 00:21 | 显示全部楼层 |阅读模式
    接入过程相对简便,只需封装一个HTTP请求,将用户的IP地址作为参数传递,便能获取到相应的国家、省份以及城市信息。

    原来的请求方式如下

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>/**
* 获取IP地址来源
*
参数内容需符合指定格式,具体表现为:姓名等于某个值,与密码等于某个值,通过“&”符号连接。
服务器端请求所采用的编码类型,例如GBK或UTF-8等。
* @return
抛出异常:编码类型不受支持
*/
将内容字符串从第3个字符开始截取,并赋值给ip变量。
    if (!Util.isIpAddress(ip)) {
        log.info("IP地址为空");
        return null;
    }
淘宝平台遭遇了IP地址服务中断,当前正采用Ip2region技术进行替代,具体信息可参考:https://github.com/lionsoul2014/ip2region。
获取城市信息的方法是将IP地址作为参数传入,然后返回相应的城市信息字符串。
日志记录显示,所获取的IP相关信息为:,具体城市信息如下:。
    // TODO 淘宝接口目前已经宕机,因此暂时注释下面代码
    try {
        // 这里调用pconline的接口
String urlStr赋值为"http://ip.taobao.com/service/getIpInfo.php";
通过访问http://whois.pconline.com.cn,我们可以获取到IP地址所对应的省份、市区信息。
获取结果字符串的操作是通过调用函数`getResult`来完成的,该函数接收三个参数:`urlStr`、`content`和`encodingString`。执行该函数后,返回的结果被赋值给变量`returnStr`。
        if (returnStr != null) {
            // 处理返回的省市区信息
记录信息:关于IP解析接口的调用结果,输出内容为:"+" + returnStr;
temp变量被赋予了一个由returnStr字符串通过逗号分隔后得到的字符串数组。
            //无效IP,局域网测试
            if (temp.length < 3) {
                return "0";
            }
            // 国家
            String country = "";
            // 区域
            String area = "";
            // 省
            String region = "";
            // 市
            String city = "";
            // 县
            String county = "";
            // 运营商
            String isp = "";
            Map<String, Object>map变量被赋予了一个值,该值是通过将返回的字符串转换成映射结构得到的,这一转换过程是由JsonUtils类中的jsonToMap方法完成的。
若map中关于"code"的键值存在非空值。
                Map<String, String> data = (Map<String, String>) map.get("data");
国家信息通过data字典中的"country"键获取,并赋值给变量country。
                area = data.get("area");
                region = data.get("region");
                city = data.get("city");
                county = data.get("area");
                isp = data.get("isp");
            }
记录信息:查询IP地址所对应的地理位置信息,包括国家、区域、地区、城市、县区以及互联网服务提供商,具体为country、area、region、city、county和isp。
创建一个新的StringBuffer对象,命名为result。
            result.append(country);
            result.append("|");
            result.append(region);
            result.append("|");
            result.append(city);
            result.append("|");
            result.append(isp);
            return result.toString();
        }


    } catch (Exception e) {
        log.error(e.getMessage());
        return null;
    }
    return null;
}
</code></pre></p>
    然而,在先前接入淘宝IP库时,时常遭遇服务中断的问题,加之QPS限制在1,因此,在访问量较大时,便无法成功获取数据。

    如今情况倒是变得更好了,该接口已经停止对外提供服务,已经彻底下线,不再允许调用。

    后面,陌溪在  冲浪的时候,发现 了  项目。

    此离线IP地址定位库准确度高达99.9%,查询速度可达到0.0x毫秒级别,其数据库文件大小仅为数MB,支持java、php、c、c++、c#等多种语言的查询绑定,并提供B树、内存等三种查询算法。

    数据汇集了若干知名IP定位信息至地名查询服务方,这些数据均源自其官方发布的精确率,经过实际测试,其定位精度确实略胜于传统的纯IP定位。这些数据主要来源于以下几家服务商提供的开放API或数据源。

    若上述开放API或数据资源未能提供开放数据,我们将不得不终止数据更新服务。

    每条 ip 数据段都固定了格式:

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>_城市Id|国家|区域|省份|城市|ISP_</code></pre></p>
    中国的数据精确到城市级别,而其他国家的部分数据仅能锁定至国家层面;在此之前的选项均为0,这一设定涵盖了你能查询到的所有大小国家。

    该数据库文件的大小仅有数MB,最小版本仅1.5MB,随着数据详细程度的提升,文件体积逐渐扩大,但截至目前,其容量仍未突破8MB。

    内置的三种查询算法

    所有查询客户端的单次查询均能在0.x毫秒内完成,并且集成了三种不同的查询算法。

    安装

    下面,就让我们给项目引入 ,进行 ip 信息转换吧

    首先引入 maven 依赖

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code><dependency>
    <groupId>org.lionsoul</groupId>
    <a style='color:#0000CC;font-size:15px;' rtifactId>ip2region</artifactId>
    <version>1.7.2</version>
</dependency>
</code></pre></p>
    然后编写一个工具类  ,首先需要加载 .db 文件

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>static {
dbPath 等于 通过 FtlArray 创建的 Ftl 文件路径 加上 "ip2region.db"。
    try {
        config = new DbConfig();
捕捉到DbMakerConfigException异常后,{
        e.printStackTrace();
    }
    try {
初始化一个DbSearcher对象,其参数包括配置信息和数据库路径,命名为searcher。
捕获到文件未找到异常后,{
        e.printStackTrace();
    }
}
</code></pre></p>
    在执行加载操作期间,必须先下载位于仓库中的数据库文件,即 .db 文件,随后将其放置到指定目录之中。

    然后,通过内置的三种算法,分别转换用户 ip 地址

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>
若数据库路径为空,则:
日志记录错误信息:“错误:ip2region.db文件无效”;
            return null;
        }
若配置项为空或搜索器为空,
系统日志记录:“错误:DbSearcher或DbConfig对象为空。”
            return null;
        }
        //查询算法
        //B-tree, B树搜索(更快)
初始化算法变量为数据库搜索器中的二叉树算法常量;即 algorithm = DbSearcher.BTREE_ALGORITHM;
        //Binary,使用二分搜索
        //DbSearcher.BINARY_ALGORITHM
        //Memory,加载内存(最快)
        //DbSearcher.MEMORY_ALGORITYM
        try {


            // 使用静态代码块,减少文件读取操作
创建一个新的DbConfig对象,命名为config。
创建了一个DbSearcher对象,该对象名为searcher,并初始化时传入了配置参数和数据库路径。
            //define the method
            Method method = null;
            switch (algorithm) {
当采用DbSearcher的BTREE算法时:
获取方法的方式为:通过调用searcher对象的getClass()方法,进而使用该方法获取getMethod()函数,该函数接收一个String.class类型的参数,最终实现获取名为"btreeSearch"的方法。
                    break;
当采用DbSearcher的二进制算法时,
通过调用searcher对象的getClass()方法,我们获取了其类信息,进而使用getMethod()方法来寻找名为"binarySearch"的方法,该方法接受一个String类型的参数。
                    break;
若采用DbSearcher所定义的内存算法模式:
获取searcher类中名为"memorySearch"的方法,该方法接受一个String类型的参数;
                    break;
                default:
            }
            DataBlock dataBlock = null;
若Util判断该IP地址并非有效,则不予以允许。
输出错误信息:“错误:无效的IP地址”
            }
dataBlock是通过调用searcher对象上的method方法,并传入ip参数,最终得到的DataBlock类型实例。
获取到的数据块中的区域信息被赋值给了字符串变量ipInfo。
若ipInfo非空,则{
ipInfo变量经过处理,去除了其中的"|"和"0"字符。
ipInfo变量经过处理,去除了其中的"0|"字符。
            }
            return ipInfo;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
</code></pre></p>
    接下来,我们将着手编写 main 函数以进行测试,结果显示,我们能够顺利地解析出 IP 地址信息。

    若IP地址源自我国境内,系统仅会显示所在省份;相对地,若IP地址位于国外,则仅会展示所属国家。鉴于此,我们有必要对该方法进行封装处理,以便获取IP地址的具体属地信息。

<p style='margin-bottom:15px;color:#555555;font-size:15px;line-height:200%;text-indent:2em;'>    <pre class="syl-page-code"><code>/**
* 获取IP属地
* @param ip
* @return
*/
    String cityInfo = getCityInfo(ip);
若cityInfo非空,则{
对cityInfo变量进行替换操作,将其中所有的竖线符号“|”更改为空格“ ”。
定义了一个名为cityList的字符串数组,该数组通过以空格为分隔符对cityInfo字符串进行分割操作得到。
        if (cityList.length > 0) {
            // 国内的显示到具体的省
若城市列表的第一个元素与“中国”字样相符。
                if (cityList.length > 1) {
                    return cityList[1];
                }
            }
            // 国外显示到国家
            return cityList[0];
        }
    }
    return "未知";
}
</code></pre></p>
    稍后,我们将尝试连接一个境外IP以检验其功能。目前,我们已成功显示出IP地址的地理位置信息了。

    抵达此处,用户的IP所在地信息已成功获取;若您希望深入了解更多功能,敬请访问相应地址进行学习。
您需要登录后才可以回帖 登录 | 立即注册

Archiver|手机版|小黑屋|关于我们

Copyright © 2001-2025, Tencent Cloud.    Powered by Discuz! X3.5    京ICP备20013102号-30

违法和不良信息举报电话:86-13718795856 举报邮箱:hwtx2020@163.com

GMT+8, 2025-6-2 14:44 , Processed in 0.081622 second(s), 17 queries .