• IP属地如何高效率识别


    概述

    IP属地显示各大平台已经有更新,抖音、今日头条、知乎、小红书等,作为一个技术,如果实现获取IP属地呢,正好近期需要做一个IP属地跳转,识别IP的归属地如果单纯的靠调用接口获取属地信息在效率上难以保证,因此给大家分享一个强大的离线IP地址定位库ip2region获取IP归属地。

    获取IP属地那么重要的步骤就是获取IP地址,怎么获取ip地址呢?

    获取用户ip地址

    HttpServletRequest 获取 IP

    1. /**
    2. * 获取ip地址
    3. */
    4. public static String getIpAddress(HttpServletRequest request) {
    5. String ip = request.getHeader("x-forwarded-for");
    6. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    7. ip = request.getHeader("Proxy-Client-IP");
    8. }
    9. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    10. ip = request.getHeader("WL-Proxy-Client-IP");
    11. }
    12. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    13. ip = request.getHeader("HTTP_CLIENT_IP");
    14. }
    15. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    16. ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    17. }
    18. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    19. ip = request.getRemoteAddr();
    20. }
    21. // 本机访问
    22. if ("localhost".equalsIgnoreCase(ip) || "127.0.0.1".equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)){
    23. // 根据网卡取本机配置的IP
    24. InetAddress inet;
    25. try {
    26. inet = InetAddress.getLocalHost();
    27. ip = inet.getHostAddress();
    28. } catch (UnknownHostException e) {
    29. e.printStackTrace();
    30. }
    31. }
    32. // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
    33. if (null != ip && ip.length() > 15) {
    34. if (ip.indexOf(",") > 15) {
    35. ip = ip.substring(0, ip.indexOf(","));
    36. }
    37. }
    38. return ip;
    39. }

     通过此方法,从请求 Header 中获取到用户的 IP 地址。

    获取IP归属地的方法

    1、在线方式

    我们可以 通过一些网络接口获取IP的归属地,例如ip.taobao.com淘宝ip地址库来获取,

    但是今天我进入淘宝ip地址库看到2022年3月31日起永久关停,如果我们使用在线的ip地址查询接口的时候也是需要防止对方接口停用到带来的损失,因此我们还有其它的方式获取ip地址属地吗?,答案是有的。

    2、离线获取IP地址属地库---Ip2region 

    1、Ip2region 是什么

    ip2region v2.0 - 是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。v1.0 旧版本: v1.0版本入口


    github 地址:https://github.com/lionsoul2014/ip2region

    2、Ip2region 特性

    标准化的数据格式、数据去重和压缩、极速查询响应、IP 数据管理框架,使用固定的 512KiB 的内存空间缓存 vector index 数据,减少一次 IO 磁盘操作,保持平均查询效率稳定在10-20微秒之间。并且准确率达到惊人的99.9% 准确率

    3、最新版本

    目前最新已更新到了 v2.0 版本,ip2region v2.0 是一个离线 IP 地址定位库和 IP 定位数据管理框架,10 微秒级别的查询效率,准提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。

    4、多查询客户端的支持

    5、ip2region xdb java 查询客户端实现

     1)maven 仓库引入

    1. <dependency>
    2. <groupId>org.lionsoulgroupId>
    3. <artifactId>ip2regionartifactId>
    4. <version>2.6.5version>
    5. dependency>

    2)下载离线IP库

    ip2region: Ip2region (2.0 - xdb) 是一个离线 IP 数据管理框架和定位库,支持亿级别的数据段,10微秒级别的查询性能,提供了许多主流编程语言的 xdb 数据管理引擎的实现。 - Gitee.com

    3)完全基于文件的查询

    1. import org.lionsoul.ip2region.xdb.Searcher;
    2. import java.io.*;
    3. import java.util.concurrent.TimeUnit;
    4. public class SearcherTest {
    5. public static void main(String[] args) {
    6. // 1、创建 searcher 对象
    7. String dbPath = "ip2region.xdb file path";
    8. Searcher searcher = null;
    9. try {
    10. searcher = Searcher.newWithFileOnly(dbPath);
    11. } catch (IOException e) {
    12. System.out.printf("failed to create searcher with `%s`: %s\n", dbPath, e);
    13. return;
    14. }
    15. String ip = "1.2.3.4";
    16. // 2、查询
    17. try {
    18. long sTime = System.nanoTime();
    19. String region = searcher.search(ip);
    20. long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
    21. System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
    22. } catch (Exception e) {
    23. System.out.printf("failed to search(%s): %s\n", ip, e);
    24. }
    25. // 3、关闭资源
    26. searcher.close();
    27. // 备注:并发使用,每个线程需要创建一个独立的 searcher 对象单独使用。
    28. }
    29. }
    30. }

    4)缓存 VectorIndex 索引

    全局缓存,每次创建 Searcher 对象的时候使用全局的 VectorIndex 缓存可以减少一次固定的 IO 操作,从而加速查询,减少 IO 压力。

    1. import org.lionsoul.ip2region.xdb.Searcher;
    2. import java.io.*;
    3. import java.util.concurrent.TimeUnit;
    4. public class SearcherTest {
    5. public static void main(String[] args) {
    6. String dbPath = "ip2region.xdb file path";
    7. // 1、从 dbPath 中预先加载 VectorIndex 缓存,并且把这个得到的数据作为全局变量,后续反复使用。
    8. byte[] vIndex;
    9. try {
    10. vIndex = Searcher.loadVectorIndexFromFile(dbPath);
    11. } catch (Exception e) {
    12. System.out.printf("failed to load vector index from `%s`: %s\n", dbPath, e);
    13. return;
    14. }
    15. // 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
    16. Searcher searcher;
    17. try {
    18. searcher = Searcher.newWithVectorIndex(dbPath, vIndex);
    19. } catch (Exception e) {
    20. System.out.printf("failed to create vectorIndex cached searcher with `%s`: %s\n", dbPath, e);
    21. return;
    22. }
    23. String ip = "1.2.3.4";
    24. // 3、查询
    25. try {
    26. long sTime = System.nanoTime();
    27. String region = searcher.search(ip);
    28. long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
    29. System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
    30. } catch (Exception e) {
    31. System.out.printf("failed to search(%s): %s\n", ip, e);
    32. }
    33. // 4、关闭资源
    34. searcher.close();
    35. // 备注:每个线程需要单独创建一个独立的 Searcher 对象,但是都共享全局的制度 vIndex 缓存。
    36. }
    37. }

    5)缓存整个 xdb 数据

    预先加载整个 ip2region.xdb 的数据到内存,然后基于这个数据创建查询对象来实现完全基于文件的查询

    1. import org.lionsoul.ip2region.xdb.Searcher;
    2. import java.io.*;
    3. import java.util.concurrent.TimeUnit;
    4. public class SearcherTest {
    5. public static void main(String[] args) {
    6. String dbPath = "C:\\Users\\Mr.Hong\\Desktop\\ip2region\\_doc\\ip2region.xdb";
    7. // 1、从 dbPath 加载整个 xdb 到内存。
    8. byte[] cBuff;
    9. try {
    10. cBuff = Searcher.loadContentFromFile(dbPath);
    11. } catch (Exception e) {
    12. System.out.printf("failed to load content from `%s`: %s\n", dbPath, e);
    13. return;
    14. }
    15. // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
    16. Searcher searcher;
    17. try {
    18. searcher = Searcher.newWithBuffer(cBuff);
    19. } catch (Exception e) {
    20. System.out.printf("failed to create content cached searcher: %s\n", e);
    21. return;
    22. }
    23. String ip = "1.2.3.4";
    24. // 3、查询
    25. try {
    26. long sTime = System.nanoTime();
    27. String region = searcher.search(ip);
    28. long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
    29. System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
    30. } catch (Exception e) {
    31. System.out.printf("failed to search(%s): %s\n", ip, e);
    32. }
    33. // 4、关闭资源 - 该 searcher 对象可以安全用于并发,等整个服务关闭的时候再关闭 searcher
    34. // searcher.close();
    35. // 备注:并发使用,用整个 xdb 数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。
    36. }
    37. }

    结束语

    使用ip2region xdb的方式查询ip地址属地效率是非常高的,可以看到我的几种不同测试中,最快的速度达到了惊人的47纳秒,可以说基本上是及时响应。所以有了这么好用的工具,并且准确率达到99%,所以以后使用IP属地查询,如果频率非常高,那么建议使用。

  • 相关阅读:
    Day09 系统设置模块设计
    Ajax基础(应用场景|jquery实现Ajax|注意事项|Ajax发送json数据|Ajax携带文件数据)
    计算机网络运维方向综合知识大全
    人工智能基础_机器学习027_L2正则化_岭回归_非稀疏性_原理解读_公式推导---人工智能工作笔记0067
    如何合理的导出help link 成HTML
    Python 遇到的报错及解决办法
    mysql比较时间
    安卓APP源码和设计报告——快递查询录入系统
    PIE-Engine 教程:水稻面积提取3—sentinel2合成月度影像宿迁市)
    登录功能(基于SpringBoot+MP+Vue实现的功能)
  • 原文地址:https://blog.csdn.net/weixin_36723038/article/details/126081205