php新手教程
转载自公众号【业余草】原文:https://juejin.cn/post/7118954784853327903老板要我做一个 IP 属地功能!我摸索了 1 天,搞定了♥️细心的朋友应该游戏会发现,最近,继新浪微博之后,头条、腾讯、抖音、知乎、快手、小红书等各大平台陆陆续续都上线了“网络用户IP地址显示功能”,境外用户显示的是国家,国内的用户显示的省份,而且此项显示无法关闭,归属地强制显游戏示。
作为技术人,那!这个功能要怎么实现呢?HttpServletRequest 获取 IP下面,我就来讲讲,Java中是如何获取IP属地的,主要分为以下几步:通过 HttpServletRequest游戏 对象,获取用户的
「IP」 地址通过 IP 地址,获取对应的省份、城市首先需要写一个 IP 获取的工具类,因为每一次用户的 Request 请求,都会携带上请求的 IP 地址放到请求头中import 游戏javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;import java.net.NetworkInterface;i游戏mport java.net.UnknownHostException;/**
* 常用获取客户端信息的工具 */publicclassNetworkUtil{/** * 获取ip地址 游戏*/publicstatic 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.getHeader(
"HTT游戏P_CLIENT_IP"); }if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 游戏 ip = request.getHeader(
"HTTP_X_FORWARDED_FOR"); }if (ip == null || ip.length() == 0 || 游戏"unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr(); }// 本机访问if ("localhost".equals游戏IgnoreCase(ip) || "127.0.0.1"
.equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)){// 根据网游戏卡取本机配置的IP InetAddress inet;
try { inet = InetAddress.getLocalHost(); 游戏 ip = inet.getHostAddress(); }
catch (UnknownHostException e) { e.p游戏rintStackTrace(); } }// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照,分割
if (null != ip && ip.le游戏ngth() > 15) {if (ip.indexOf(",") > 15) { ip = ip.substring(0, ip.indexOf(
",")); 游戏 } }return ip; }/** * 获取mac地址 */publicstatic String getMacAddress()
throws Ex游戏ception {// 取mac地址byte[] macAddressBytes = NetworkInterface.getByInetAddress(InetAddress.getLocalHos游戏t()).getHardwareAddress();
// 下面代码是把mac地址拼装成String StringBuilder 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] &
0xF游戏F); sb.append(s.length() == 1 ? 0 + s : s); }return sb.toString().trim().toUpperCa游戏se();
}}通过此方法,从请求Header中获取到用户的IP地址。之前我在做的项目中,也有获取IP地址归属地省份、城市的需求,用的是:淘宝IP库。地址:https://ip.taobao.com/。游戏

taobao的ip库下线了再见ip.taobao,全网显示 IP 归属地。

ip归属地原来的请求源码如下:


可以看到日志log文件中,大量的the request over max qps for use游戏r问题。

留下了难过的泪水Ip2region下面,给大家介绍下之前在Github冲浪时发现的今天的主角:Ip2region开源项目,github地址:https://github.com/lionsou游戏l2014/ip2region
❝目前最新已更新到了v2.0版本,ip2region v2.0是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,准提供了众多主流编程语言的 xdb 游戏数据生成和查询客户端实现❞99.9%准确率:
❝数据聚合了一些知名ip到地名查询提供商的数据,这些是他们官方的的准确率,经测试着实比经典的纯真IP定位准确一些ip2region的数据聚合自以下服务商的开游戏放API或者数据(升级程序每秒请求次数2到4次):。
01, >80%, 淘宝IP地址库, http://ip.taobao.com/%5C02, ≈10%, GeoIP, https://geoip.游戏com/%5C03, ≈2%, 纯真IP库, http://www.cz88.net/%5C
❞备注:如果上述开放API或者数据都不给开放数据时ip2region将停止数据的更新服务多查询客户端的支持已游戏经集成的客户端有:java、C#、php、c、python、nodejs、php扩展(php5和php7)、golang、rust、lua、lua_c, nginx。
binding描述开发状态bina游戏ry查询耗时b-tree查询耗时memory查询耗时cANSC c binding已完成0.0x毫秒0.0x毫秒0.00x毫秒c#c# binding已完成0.x毫秒0.x毫秒
0.1x毫秒golang游戏golang binding已完成0.x毫秒0.x毫秒0.1x毫秒javajava binding已完成0.x毫秒0.x毫秒0.1x毫秒lualua实现的binding已完成0.x毫秒
0.x毫秒0.x游戏毫秒lua_clua的c扩展已完成0.0x毫秒0.0x毫秒0.00x毫秒nginxnginx的c扩展已完成0.0x毫秒0.0x毫秒0.00x毫秒nodejsnodejs已完成0.x毫秒0.x毫秒
0.1游戏x毫秒phpphp实现的binding已完成0.x毫秒0.1x毫秒0.1x毫秒php5_extphp5的c扩展已完成0.0x毫秒0.0x毫秒0.00x毫秒php7_extphp7的c扩展已完成0.0毫游戏秒
0.0x毫秒0.00x毫秒pythonpython bindng已完成0.x毫秒0.x毫秒0.x毫秒rustrust binding已完成0.x毫秒0.x毫秒0.x毫秒Ip2region V2.0 游戏特性
「1、标准化的数据格式」每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|ISP,只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后前的选项全部是0游戏「2、数据去重和压缩」。
xdb 格式生成程序会自动去重和压缩部分数据,默认的全部 IP 数据,生成的 ip2region.xdb 数据库是 11MiB,随着数据的详细度增加数据库的大小也慢慢增大「3、游戏极速查询响应」即使是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别,可通过如下两种方式开启内存加速查询:。
vIndex 索引缓存 :使用固定的 512KiB 的内存空间缓存 vector 游戏index 数据,减少一次 IO 磁盘操作,保持平均查询效率稳定在10-20微秒之间xdb 整个文件缓存:将整个 xdb 文件全部加载到内存,内存占用等同于 xdb 文件大小,无磁盘 IO 操作,保持游戏微秒级别的查询效率。
「4、极速查询响应」v2.0 格式的 xdb 支持亿级别的 IP 数据段行数,region 信息也可以完全自定义,例如:你可以在 region 中追加特定业务需求的数据,例如:GP游戏S信息/国际统一地域信息编码/邮编等。
也就是你完全可以使用 ip2region 来管理你自己的 IP 定位数据ip2region xdb java 查询客户端实现「使用方式」引入maven仓库:org游戏.lionsoul
ip2region2.6.4「完全基于文件的查询」import org.lionsoul.ip2region.xdb.Searcher;
import java.io.*;import游戏 java.util.concurrent.TimeUnit;publicclassSearcherTest{publicstaticvoidmain(String[] args)
{// 1、创建 s游戏earcher 对象 String dbPath = "ip2region.xdb file path"; Searcher searcher = null
;try { 游戏 searcher = Searcher.newWithFileOnly(dbPath); } catch (IOException e) { S游戏ystem.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 = searche游戏r.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 对象单独使用 }}「缓存VectorIndex索引」我们可以提前从 xdb 文件中加载出来 Vector游戏Index 数据,然后全局缓存,每次创建 Searcher 对象的时候使用全局的 VectorIndex 缓存可以减少一次固定的 IO 操作,从而加速查询,减少 IO 压力。
import org.li游戏onsoul.ip2region.xdb.Searcher;import java.io.*;import java.util.concurrent.TimeUnit;public
classSearc游戏herTest{publicstaticvoidmain(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 lo游戏ad vector index from `%s`: %s\n"
, dbPath, e);return; }// 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询游戏对象 Searcher searcher;try {
searcher = Searcher.newWithVectorIndex(dbPath, vIndex); } ca游戏tch (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 = Sy游戏stem.nanoTime(); String region = searcher.search(ip);
long cost = TimeUnit.NANOSECONDS.toM游戏icros((long) (System.nanoTime() - sTime)); System.out.printf(
"{region: %s, ioCount: %d, t游戏ook: %d μs}\n", region, searcher.getIOCount(), cost); } catch (Exception e) {
System.out.print游戏f("failed to search(%s): %s\n", ip, e); }// 备注:每个线程需要单独创建一个独立的 Searcher 对象,但是都共享全局的制度 vIndex 游戏缓存。
}}「缓存整个xdb数据」我们也可以预先加载整个 ip2region.xdb 的数据到内存,然后基于这个数据创建查询对象来实现完全基于文件的查询,类似之前的 memory searchimpor游戏t。
org.lionsoul.ip2region.xdb.Searcher;import java.io.*;import java.util.concurrent.TimeUnit;publiccl游戏ass
SearcherTest{publicstaticvoidmain(String[] args){ String dbPath = "ip2region.xdb file path游戏";// 1、从 dbPath 加载整个 xdb 到内存。
byte[] cBuff;try { cBuff = Searcher.loadContentFromFile(dbPa游戏th); } catch (Exception e) {
System.out.printf("failed to load content from `%s`: %s\n", dbPat游戏h, e);return; }// 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
Searcher searcher;try { searcher =游戏 Searcher.newWithBuffer(cBuff); } catch (Exception e) {
System.out.printf("failed to create co游戏ntent 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.NANOS游戏ECONDS.toMicros((long) (System.nanoTime() - sTime)); System.out.printf(
"{region: %s, ioCo游戏unt: %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 对象做成全局对象去跨线程访问。
}}IDEA中做个测试
IDEA中做个测试完全基于文件的查询ip属地国内的话,会展示省份,国外的话,只会展示国家。可以通过如下图这个方法进游戏行进一步封装,得到获取IP属地的信息。
完全基于文件的查询❝下面是官网给出的命令运行jar方式给出的测试demo,可以理解下❞编译测试程序通过 maven 来编译测试程序# cd 到 java bind游戏ing 的根目录cd binding/java/。
mvn compile package然后会在当前目录的 target 目录下得到一个 ip2region-{version}.jar 的打包文件查询游戏测试可以通过 java -jar ip2region-{version}.jar search 命令来测试查询:。
➜ java git:(v2.0_xdb) ✗ java -jar target/i游戏p2region-2.6.0.jar searchjava -jar ip2region-{version}.jar search [command options]
options: --db str游戏ing ip2region binary xdb file path --cache-policy string cache policy: file/vectorIn游戏dex/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: vect游戏orIndextype quit to exitip2region>> 1.2.3.4{region: 美国|
0|华盛顿|0|谷歌, ioCount: 7, took: 82 μs}ip2region游戏>>输入 ip 即可进行查询测试,也可以分别设置 cache-policy 为 file/vectorIndex/content 来测试三种不同缓存实现的查询效果。
bench 测试可以通过 java 游戏-jar ip2region-{version}.jar bench 命令来进行 bench 测试,一方面确保 xdb 文件没有错误,一方面可以评估查询性能:➜ java git:(v2
.0_xdb游戏) ✗ java -jar target/ip2region-2.6.0.jar benchjava -jar ip2region-{version}.jar bench [command optio游戏ns]
options: --db string ip2region binary xdb file path --src string source 游戏ip text file path
--cache-policy string cache policy: file/vectorIndex/content例如:通过默认的 data/ip2reg游戏ion.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: v游戏ectorIndex, total: 3417955, took: 8s, cost: 2 μs/op}可以通过分别设置 cache-policy 为 file/vectorIndex/content游戏 来测试三种不同缓存实现的效果。
@Note: 注意 bench 使用的 src 文件要是生成对应 xdb 文件相同的源文件❝到这里获取用户IP属地已经完成啦,这篇文章介绍的v2.0版本,有兴趣的小伙伴游戏可以登录上门的github地址了解下v1.0版本
❞如若觉得有用,欢迎收藏+点赞!
说个题外话,鸟哥是个比较喜欢折腾的程序员,业余喜欢开发自己网站、小程序、App等,这些东西统统离不开服务器!最近就围绕服游戏务器的主题创建了一个微信群,喜欢玩服务器或者想自己开发一款产品的读者可以进来,相互学习交流!
群通知中给大家分享了一套搭建服务器的视频教程哦非常适合新手学习!我也会时不时的带大家撸点和服务器相关的优惠券游戏!不感兴趣,不喜欢折腾的就没必要凑着闹了!识别二维码,添加微信后发送【服务器】即可获取邀请链接。
这是我部署的机器人,请勿调戏!推荐阅读发小被绿,我竭尽所学黑科技,动用云控捉奸寻找证据….去他妈的某日葵游戏!不就远程控制嘛,老子自己搭建!我也折腾了一款百度网盘....不会被抓进去吧~连夜给学妹肝了一篇搭建个人网站的教程,这就送过去了,兄弟们把把关!
亲爱的读者们,感谢您花时间阅读本文。如果您对本文有任何疑游戏问或建议,请随时联系我。我非常乐意与您交流。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。