细心的小伙伴可能会发现,最近蘑菇新上线了 IP 属地的功能,小伙伴在发表动态、发表评论以及聊天的时候,都会显示自己的 IP 属地信息

编辑切换为居中

添加图片注释,不超过 140 字(可选)

动态显示IP属地

在蘑菇群聊中,也 可 以 展 示 IP 属 地,下面是小伙伴们在交流群中显示的

下面,我就来讲讲,Java 中是如何获取 IP 属地的,主要分为以下几步

  • 通过 HttpServletRequest 对象,获 取 用户的 IP 地址

  • 通过 IP 地址,获取对应的省份、城市

首先需要写一个 IP 获取的工具类,因为每一次用户的 Request 请 求,都会携带上请求的 IP 地 址放到请求头中。



public class IpUtil { public static String getIpAddr(ServerHttpRequest request) { HttpHeaders headers = request.getHeaders(); String ipAddress = headers.getFirst("X-Forwarded-For"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = headers.getFirst("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = headers.getFirst("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddress().getAddress().getHostAddress(); if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) { // 根据网卡取本机配置的IP try { InetAddress inet = InetAddress.getLocalHost(); ipAddress = inet.getHostAddress(); } catch (UnknownHostException e) { log.error("根据网卡获取本机配置的IP异常", e); } } } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ipAddress != null && ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.split(",")[0]; } return ipAddress; } }

这里有三个名词,分别是

  • X-Forwarded-For:一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真 实 IP 地址。每个 IP 地址,每个值通过逗号+空格分开,最左边是最原始客户端的 IP 地址,中间如果有多层代理,每⼀层代理会将连接它的客户端 IP 追加在 X-Forwarded-For 右边。

  • X-Real-IP:一般只记录真实发出请求的客户端IP

  • Proxy-Client-IP:这个一般是经过 Apache http 服务器的请求才会有,用 Apache http 做代理时一般会加上 Proxy-Client-IP 请求头

  • WL-Proxy-Client-IP:也是通过 Apache http 服务器,在 weblogic 插件加上的头。

在我们获取到用户 的 IP 地址后,那么就可以获取对应的 ip 信息了

蘑菇最开始使用的是淘宝 IP 库

地址:https://ip.taobao.com/

编辑切换为居中

添加图片注释,不超过 140 字(可选)

接入方式也比较简单,就是通过封装一个 http 请求,传 入用户的 ip 作为参数,就可以返回 ip 对应的国家,省,城市 信息

编辑切换为居中

添加图片注释,不超过 140 字(可选)

原来的请求方式如下



/** * 获取IP地址来源 * * @param content 请求的参数 格式为:name=xxx&pwd=xxx * @param encodingString 服务器端请求编码。如GBK,UTF-8等 * @return * @throws UnsupportedEncodingException */ public static String getAddresses(String content, String encodingString) { String ip = content.substring(3); if (!Util.isIpAddress(ip)) { log.info("IP地址为空"); return null; } // 淘宝IP宕机,目前使用Ip2region:https://github.com/lionsoul2014/ip2region String cityInfo = getCityInfo(ip); log.info("返回的IP信息:{}", cityInfo); // TODO 淘宝接口目前已经宕机,因此暂时注释下面代码 try { // 这里调用pconline的接口 String urlStr = "http://ip.taobao.com/service/getIpInfo.php"; // 从http://whois.pconline.com.cn取得IP所在的省市区信息 String returnStr = getResult(urlStr, content, encodingString); if (returnStr != null) { // 处理返回的省市区信息 log.info("调用IP解析接口返回的内容:" + returnStr); String[] temp = returnStr.split(","); //无效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(returnStr); if (map.get("code") != null) { Map<String, String> data = (Map<String, String>) map.get("data"); country = data.get("country"); area = data.get("area"); region = data.get("region"); city = data.get("city"); county = data.get("area"); isp = data.get("isp"); } log.info("获取IP地址对应的地址" + country + "=" + area + "=" + region + "=" + city + "=" + county + "=" + isp); StringBuffer result = new StringBuffer(); 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; }

但是,之前接入淘宝 IP 库的时候,也经常会遇到服务不可用的情况,并且由于限制了 QPS 为 1,所以如果访问量大的话,就没办法获取了。

而到现在的话倒好了,这个接口也不对外提供服务了,直接下线了,不让调用了。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

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

一个准确率 99.9% 的离线 IP 地址定位库,0.0x 毫秒级查询,ip2region.db 数据库只有数 MB,提供了 java,php,c,python,nodejs,golang,c# 等查询绑定和Binary,B树,内存三种查询算法。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

数据聚合了一些知名 ip 到地名查询提供商的数据,这些是他们官方的的准确率,经测试着实比经典的纯真 IP 定位准确一些。ip2region 的 数据聚合自以下服务商的开放 API 或者数据。

  • 80%, 淘宝IP地址库, http://ip.taobao.com/

  • ≈10%, GeoIP, https://geoip.com/

  • ≈2%, 纯真IP库, http://www.cz88.net/

备注:如果上述开放API或者数据都不给开放数据时ip2region将停止数据的更新服务。

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



_城市Id|国家|区域|省份|城市|ISP_

只有中国的数据精确到了城市,其他国家有部分数据只能定位到国家,后 前的选项全部是 0,已经包含了全部你能查到的大大小小的国家

生成的数据库文件 ip2region.db 只有几 MB,最小的版本只有 1.5MB,随着数据的详细度增加数据库的大小也慢慢增大,目前还没超过 8MB。

内置的三种查询算法

全部的查询客户端单次查询都在 0.x 毫秒级别,内置了三种查询算法

  • memory 算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。

  • binary 算法:基于二分查找,基于ip2region.db文件,不需要载入内存,单次查询在0.x毫秒级别。

  • b-tree 算法:基于btree算法,基于ip2region.db文件,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快。

ip2region安装

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

首先引入 maven 依赖



<dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>1.7.2</version> </dependency>

然后编写一个工具类 IpUtils ,首先需要加载 ip2region.db 文件



static { dbPath = createFtlFileByFtlArray() + "ip2region.db"; try { config = new DbConfig(); } catch (DbMakerConfigException e) { e.printStackTrace(); } try { searcher = new DbSearcher(config, dbPath); } catch (FileNotFoundException e) { e.printStackTrace(); } }

在加载的时候,需要下载仓库中的 ip2region.db 文件,然后放到 resource 目录下

编辑

添加图片注释,不超过 140 字(可选)

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



public static String getCityInfo(String ip) { if (StringUtils.isEmpty(dbPath)) { log.error("Error: Invalid ip2region.db file"); return null; } if(config == null || searcher == null){ log.error("Error: DbSearcher or DbConfig is null"); return null; } //查询算法 //B-tree, B树搜索(更快) int algorithm = DbSearcher.BTREE_ALGORITHM; //Binary,使用二分搜索 //DbSearcher.BINARY_ALGORITHM //Memory,加载内存(最快) //DbSearcher.MEMORY_ALGORITYM try { // 使用静态代码块,减少文件读取操作 // DbConfig config = new DbConfig(); // DbSearcher searcher = new DbSearcher(config, dbPath); //define the method Method method = null; switch (algorithm) { case DbSearcher.BTREE_ALGORITHM: method = searcher.getClass().getMethod("btreeSearch", String.class); break; case DbSearcher.BINARY_ALGORITHM: method = searcher.getClass().getMethod("binarySearch", String.class); break; case DbSearcher.MEMORY_ALGORITYM: method = searcher.getClass().getMethod("memorySearch", String.class); break; default: } DataBlock dataBlock = null; if (Util.isIpAddress(ip) == false) { System.out.println("Error: Invalid ip address"); } dataBlock = (DataBlock) method.invoke(searcher, ip); String ipInfo = dataBlock.getRegion(); if (!StringUtils.isEmpty(ipInfo)) { ipInfo = ipInfo.replace("|0", ""); ipInfo = ipInfo.replace("0|", ""); } return ipInfo; } catch (Exception e) { e.printStackTrace(); } return null; }

下面,我们编写 main 函数进行测试,发现可以正常的解析出 ip 信息

编辑切换为居中

添加图片注释,不超过 140 字(可选)

由于 ip 属地在国内的话,只会展示省份,而国外的话,只会展示国家。所以我们还需要对这个方法进行一下封装,得到获取 IP 属地的信息。



/** * 获取IP属地 * @param ip * @return */ public static String getIpPossession(String ip) { String cityInfo = getCityInfo(ip); if (!StringUtils.isEmpty(cityInfo)) { cityInfo = cityInfo.replace("|", " "); String[] cityList = cityInfo.split(" "); if (cityList.length > 0) { // 国内的显示到具体的省 if ("中国".equals(cityList[0])) { if (cityList.length > 1) { return cityList[1]; } } // 国外显示到国家 return cityList[0]; } } return "未知"; }

下面,我们在找一个 国外的 IP 测试一下效果。可以看到已经能够正常的显示 IP 属地信息了~

编辑切换为居中

添加图片注释,不超过 140 字(可选)

到这里如果获取用户的 IP 属地已经完成啦,如果想要了解关于更多 ip2region 的功能,欢迎访问其 Github 地址进行学习。

项目地址

https://github.com/lionsoul2014/ip2region

资源获取:

大家点赞、收藏、关注、评论啦 、查看

全网显示 IP 归属地,用上这个开源库,实现也太简单了相关推荐

  1. 全网显示 IP 归属地,可以考虑这个开源库

    最近微博等平台都上线  IP 属地功能. 下面,我就来讲讲,Java 中是如何获取 IP 属地的,主要分为以下几步 通过 HttpServletRequest 对象,获取用户的 IP 地址 通过 IP ...

  2. 再见ip.taobao,全网显示 IP 归属地,用上这个开源库,实现也太简单了!

    细心的朋友应该会发现,最近,继新浪微博之后,头条.腾讯.抖音.知乎.快手.小红书等各大平台陆陆续续都上线了"网络用户IP地址显示功能",境外用户显示的是国家,国内的用户显示的省份, ...

  3. 公众号显示IP归属地,有多少人会现出原形?

    假期吃了一个大瓜,著名的大V连岳翻车,因为微信公众号文章发表于日本被骂上热搜. 网友群嘲他"身在日本劝人爱中,坐办公室写稿劝人进厂,身为丁克劝人三胎". 还有很多假装在国内/国外的 ...

  4. 全网进入“IP归属地”模式,键盘侠老实了,这些人也慌了

    最近一段比较火的事情可能就是全网进入"IP归属地"模式这件事了,其中包括某音.某手.某乎等等一系列自媒体平台,官方的每一次动作都会有一些人起飞,同样,也会有一部分人发慌了. 起飞的 ...

  5. 为何这些软件要显示ip归属地

    4 月 15 日消息,抖音安全中心近日宣布,为维护真实有序的讨论氛围,减少冒充热点事件当事人.恶意造谣.蹭流量等不良行为,抖音拟在个人主页等位置展示帐号 IP 属地,相关功能在 4 月底进行测试,将根 ...

  6. 手把手教你实现显示IP归属地

    手把手教你实现显示IP归属地 实现原理 获取IP地址 调用IP归属地接口: 近年来,根据<国家互联网用户账号名称信息管理规定>要求互联网用户账号服务平台标注IP地址属地信息,微信公众号.抖 ...

  7. 100个Github上Android开源库

    项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, ...

  8. centos7 输入 ifconfig 不显示 ip 地址 连接不上的解决方法(亲测成功)

    最近又把自己的虚拟机打开了玩玩集群,遇到一个小问题,我发现虚拟机的内存不够了,就把虚拟机关机加大了内存,谁知道开机后,ifconfig或者ip addr 显示没有ip地址,只显示一个lo,没有ens3 ...

  9. NLP模型也有“老师”了!装上这个开源库,1毫秒纠正语法错误

    杨净 发自 凹非寺 量子位 报道 | 公众号 QbitAI 当NLP模型产生了语法错误,怎么办? 比如,He wants that you send him an email. 没关系,现在可以像小时 ...

最新文章

  1. CAN'T TAKE MY EYES OF YOU
  2. 1061 判断题 (15 分)
  3. 草稿 DataGridView 控件 1129
  4. Linux配置nginx打开报404,Linux下Nginx配置404页面的方法
  5. Android studio无法创建类和接口问题解决办法。提示 Unable to parse template Class
  6. 中国内鼻扩张器市场趋势报告、技术动态创新及市场预测
  7. SQL Server 默认跟踪 -- 捕获事件详解
  8. 深度神经网络基本问题的原理详细分析和推导
  9. 锁的实现原理—1,为什么会有锁?
  10. RFCOMM简单介绍
  11. 《舞!舞!舞!》读后感
  12. whatamitoyou-小白详解
  13. windows保护无法启动修复服务器,如何解决win10“Windows资源保护无法启动修复服务”错误 | MOS86...
  14. 第二阶段--团队冲刺--第十天
  15. Android设置drawableRight或drawableLeft后设置图标与文字间距
  16. 【学习笔记】【算法】【智能优化】粒子群优化(PSO)
  17. 华为2022硬件逻辑笔试题
  18. 5种方法完美解决android软键盘挡住输入框方法详解
  19. Bootstrap5不再支持IE浏览器,在网站顶部给IE浏览器访客给予提示
  20. [转载]有经验的人对各种常用IC芯片使用感受

热门文章

  1. 服务器修改字体,Win10 1909默认字体怎么修改?Win10 1909默认字体修改教程
  2. Residual Networks(吴恩达课程)
  3. 租房小程序登顶码云热门
  4. 【计算机网络】【运输层-5】
  5. iNFTnews|沉浸式人工智能可能会重塑一切
  6. SpringMVC源代码学习外传(二)如何在重定向时传递参数FlashMap
  7. Google 和 Googol - 背景趣味
  8. 笔记本/台式机改造成centos7服务器 + 宝塔面板服务器磁盘挂载(亲测,能打版)
  9. java 监控 局域网_使用Java实现简单的局域网设备扫描
  10. fritzing导入元件_推荐一款炫酷的电路图软件-Fritzing