pc网站 手机网站,在线seo优化工具,济宁营销网站建设,什么网站做h5好细心的朋友们可能已经发现了#xff0c;先在抖音、知乎、快手、小红书等这些平台已经上线了“网络用户显示 IP 的功能”#xff0c;境外用户显示的是国家#xff0c;国内的用户显示的省份#xff0c;而且此项显示无法关闭#xff0c;归属地强制显示。
1获取用户 IP 地址 …细心的朋友们可能已经发现了先在抖音、知乎、快手、小红书等这些平台已经上线了“网络用户显示 IP 的功能”境外用户显示的是国家国内的用户显示的省份而且此项显示无法关闭归属地强制显示。
1获取用户 IP 地址
HttpServletRequest 获取 IP
首先我们来看一下在 Java 中是如何获取到 IP 属地的主要有以下两步: 通过 HttpServletRequest 对象获取用户的 「IP」 地址 通过 IP 地址获取对应的省份、城市]
首先我们这里写一个工具类用于获取 IP 地址因为用户的每次 Request 请求都会携带请求的 IP 地址放到请求头中所以我们可以通过截取请求中的 IP 来获取 IP 地址
/*** 网络工具类** author a hrefhttps://github.com/liyupi程序员鱼皮/a* from a hrefhttps://yupi.icu编程导航知识星球/a*/
public class NetUtils {/*** 获取客户端 IP 地址** param request* return*/public static String getIpAddress(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();if (ip.equals(127.0.0.1)) {// 根据网卡取本机配置的 IPInetAddress inet null;try {inet InetAddress.getLocalHost();} catch (Exception e) {e.printStackTrace();}if (inet ! null) {ip inet.getHostAddress();}}}// 多个代理的情况第一个IP为客户端真实IP,多个IP按照,分割if (ip ! null ip.length() 15) {if (ip.indexOf(,) 0) {ip ip.substring(0, ip.indexOf(,));}}// 本机访问if (localhost.equalsIgnoreCase(ip) || 127.0.0.1.equalsIgnoreCase(ip) || 0:0:0:0:0:0:0:1.equalsIgnoreCase(ip)){// 根据网卡取本机配置的IPInetAddress inet;try {inet InetAddress.getLocalHost();ip inet.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}}// 如果查找不到 IP,可以返回 127.0.0.1可以做一定的处理但是这里不考虑// if (ip null) {// return 127.0.0.1;// }return ip;}/*** 获取mac地址*/public static String getMacAddress() throws Exception {// 取mac地址byte[] macAddressBytes NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();// 下面代码是把mac地址拼装成StringStringBuilder sb new StringBuilder();for (int i 0; i macAddressBytes.length; i) {if (i ! 0) {sb.append(-);}// mac[i] 0xFF 是为了把byte转化为正整数String s Integer.toHexString(macAddressBytes[i] 0xFF);sb.append(s.length() 1 ? 0 s : s);}return sb.toString().trim().toUpperCase();}
}2获取用户的 IP 地址属地
淘宝库获取用户 IP 地址属地
通过这个方法就可以重请求头中获取到用户的 IP 地址了然后接下来就是 IP 地址归属地省份、城市的获取了这里可以用很多 IP 地址查询的库进行查询这里用一个库来测试一下。 淘宝 IP 地址库ip.taobao.com/ 不过淘宝的 IP 地址查询库已经在 2022 年 3 月 31 日下线了这里我们就不能使用它了只能另辟蹊径了。 这里我们截取一段之前淘宝货期 IP 地址的源码然后一起来看一下。
这里可以看到在日志文件中出现了大量的 the request over max qps for user 问题。
虽然这个方法已经寄了但是我们求知的道路可以停吗肯定不可以啊这里我们就来整一个新的获取 IP 地址属地的方法也就是我们今天文章的主角Ip2region。
Ip2region 介绍 这个开源库目前已经更新到了 V2 的版本现在的它是一个强大的离线IP地址定位库和IP定位数据管理框架其达到了微秒级别的查询效率还提供了众多主流编程语言的 xdb 数据生成和查询客户端实现可以说是非常得好用今天这篇文章我们主要针对其 V2 版本进行讲解 3Ip2region 详解
高达 99.9 % 的查询准确率
数据聚合了一些知名 ip 到地名查询提供商的数据这些是他们官方的的准确率经测试着实比经典的纯真 IP 定位准确一些。
ip2region 的数据聚合自以下服务商的开放 API 或者数据(升级程序每秒请求次数 2 到 4 次)比例如下 80%, 淘宝 IP 地址库, ip.taobao.com/%5C ≈10%, GeoIP, geoip.com/%5C ≈2%, 纯真 IP 库, www.cz88.net/%5C
Ip2region V2.0 特性
1、IP 数据管理框架
xdb 支持亿级别的 IP 数据段行数默认的 region 信息都固定了格式国家|区域|省份|城市|ISP缺省的地域信息默认是0。
region 信息支持完全自定义例如你可以在 region 中追加特定业务需求的数据例如GPS信息/国际统一地域信息编码/邮编等。也就是你完全可以使用 ip2region 来管理你自己的 IP 定位数据。
2、数据去重和压缩
xdb 格式生成程序会自动去重和压缩部分数据默认的全部 IP 数据生成的 ip2region.xdb 数据库是 11MiB随着数据的详细度增加数据库的大小也慢慢增大。
3、极速查询响应
即使是完全基于 xdb 文件的查询单次查询响应时间在十微秒级别可通过如下两种方式开启内存加速查询 vIndex 索引缓存使用固定的 512KiB 的内存空间缓存 vector index 数据减少一次 IO 磁盘操作保持平均查询效率稳定在10-20微秒之间。 xdb 整个文件缓存将整个 xdb 文件全部加载到内存内存占用等同于 xdb 文件大小无磁盘 IO 操作保持微秒级别的查询效率。
多语言以及查询客户端的支持
已经客户端有Java、C#、php、C、Python、Node.js、PHP 拓展PHP 5 和 PHP 7等主要如下 Ip2region xdb Java 查询客户端实现
这里简单展示一下 Java 的实现这里使用开发中常用的 Maven 实现的方式
1. 引入 Maven 仓库
由于项目使用Spring 的方式构建这里可以选择使用引入 Spring 的 starter 的方式进行
dependencygroupIdcom.github.hiwepy/groupIdartifactIdip2region-spring-boot-starter/artifactIdversion2.0.1.RELEASE/version
/dependencydependencygroupIdorg.lionsoul/groupIdartifactIdip2region/artifactIdversion2.7.0/version
/dependency在引入 Maven 依赖之后我们这里引入几种实现的方式
2. 实现方式 1【基于文件查询】
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.*;
import java.util.concurrent.TimeUnit;public class SearcherTest {public static void main(String[] args) {// 1、创建 searcher 对象String dbPath ip2region.xdb file path;Searcher searcher null;try {searcher Searcher.newWithFileOnly(dbPath);} catch (IOException e) {System.out.printf(failed to create searcher with %s: %s\n, dbPath, e);return;}// 2、查询try {String ip 1.2.3.4;long sTime System.nanoTime();String region searcher.search(ip);long cost TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));System.out.printf({region: %s, ioCount: %d, took: %d μs}\n, region, searcher.getIOCount(), cost);} catch (Exception e) {System.out.printf(failed to search(%s): %s\n, ip, e);}// 3、备注并发使用每个线程需要创建一个独立的 searcher 对象单独使用。}
}3. 实现方式 2【缓存VectorIndex索引】
我们可以提前从 xdb 文件中加载出来 VectorIndex 数据然后全局缓存每次创建 Searcher 对象的时候使用全局的 VectorIndex 缓存可以减少一次固定的 IO 操作从而加速查询减少 IO 压力。
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.*;
import java.util.concurrent.TimeUnit;public class SearcherTest {public static void main(String[] args) {String dbPath ip2region.xdb file path;// 1、从 dbPath 中预先加载 VectorIndex 缓存并且把这个得到的数据作为全局变量后续反复使用。byte[] vIndex;try {vIndex Searcher.loadVectorIndexFromFile(dbPath);} catch (Exception e) {System.out.printf(failed to load vector index from %s: %s\n, dbPath, e);return;}// 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。Searcher searcher;try {searcher Searcher.newWithVectorIndex(dbPath, vIndex);} catch (Exception e) {System.out.printf(failed to create vectorIndex cached searcher with %s: %s\n, dbPath, e);return;}// 3、查询try {String ip 1.2.3.4;long sTime System.nanoTime();String region searcher.search(ip);long cost TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));System.out.printf({region: %s, ioCount: %d, took: %d μs}\n, region, searcher.getIOCount(), cost);} catch (Exception e) {System.out.printf(failed to search(%s): %s\n, ip, e);}// 备注每个线程需要单独创建一个独立的 Searcher 对象但是都共享全局的制度 vIndex 缓存。}
}4. 实现方式 3「缓存整个 xdb 数据」
我们也可以预先加载整个 ip2region.xdb 的数据到内存然后基于这个数据创建查询对象来实现完全基于文件的查询类似之前的 memory search。
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.*;
import java.util.concurrent.TimeUnit;public class SearcherTest {public static void main(String[] args) {String dbPath ip2region.xdb file path;// 1、从 dbPath 加载整个 xdb 到内存。byte[] cBuff;try {cBuff Searcher.loadContentFromFile(dbPath);} catch (Exception e) {System.out.printf(failed to load content from %s: %s\n, dbPath, e);return;}// 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。Searcher searcher;try {searcher Searcher.newWithBuffer(cBuff);} catch (Exception e) {System.out.printf(failed to create content cached searcher: %s\n, e);return;}// 3、查询try {String ip 1.2.3.4;long sTime System.nanoTime();String region searcher.search(ip);long cost TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));System.out.printf({region: %s, ioCount: %d, took: %d μs}\n, region, searcher.getIOCount(), cost);} catch (Exception e) {System.out.printf(failed to search(%s): %s\n, ip, e);}// 备注并发使用用整个 xdb 数据缓存创建的查询对象可以安全的用于并发也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。}
}5. 编译测试程序
通过 maven 来编译测试程序。
# cd 到 java binding 的根目录
cd binding/java/
mvn compile package然后会在当前目录的 target 目录下得到一个 ip2region-{version}.jar 的打包文件。
6. 查询测试
可以通过 java -jar ip2region-{version}.jar search 命令来测试查询
➜ java git:(v2.0_xdb) ✗ java -jar target/ip2region-2.6.0.jar search
java -jar ip2region-{version}.jar search [command options]
options:--db string ip2region binary xdb file path--cache-policy string cache policy: file/vectorIndex/content例如使用默认的 data/ip2region.xdb 文件进行查询测试
➜ java git:(v2.0_xdb) ✗ java -jar target/ip2region-2.6.0.jar search --db../../data/ip2region.xdb
ip2region xdb searcher test program, cachePolicy: vectorIndex
type quit to exit
ip2region 1.2.3.4
{region: 美国|0|华盛顿|0|谷歌, ioCount: 7, took: 82 μs}
ip2region输入 ip 即可进行查询测试也可以分别设置 cache-policy 为 file/vectorIndex/content 来测试三种不同缓存实现的查询效果。
4bench 测试
可以通过 java -jar ip2region-{version}.jar bench 命令来进行 bench 测试一方面确保 xdb 文件没有错误一方面可以评估查询性能
➜ java git:(v2.0_xdb) ✗ java -jar target/ip2region-2.6.0.jar bench
java -jar ip2region-{version}.jar bench [command options]
options:--db string ip2region binary xdb file path--src string source ip text file path--cache-policy string cache policy: file/vectorIndex/content例如通过默认的 data/ip2region.xdb 和 data/ip.merge.txt 文件进行 bench 测试
➜ java git:(v2.0_xdb) ✗ java -jar target/ip2region-2.6.0.jar bench --db../../data/ip2region.xdb --src../../data/ip.merge.txt
Bench finished, {cachePolicy: vectorIndex, total: 3417955, took: 8s, cost: 2 μs/op}可以通过分别设置 cache-policy 为 file/vectorIndex/content 来测试三种不同缓存实现的效果。
Note: 注意 bench 使用的 src 文件要是生成对应 xdb 文件相同的源文件。
最后说一句(求关注!别白嫖)
如果这篇文章对您有所帮助或者有所启发的话求一键三连点赞、转发、在看。
关注公众号woniuxgg在公众号中回复笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记回复面试、开发手册、有超赞的粉丝福利