日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

老板要我做一个 IP 属地功能,要求准确率99.9%!

發布時間:2024/1/18 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 老板要我做一个 IP 属地功能,要求准确率99.9%! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好,我是老趙!

老板要我做一個 IP 屬地功能!我摸索了 1 天,搞定了。??

細心的朋友應該會發現,最近,繼新浪微博之后,頭條、騰訊、抖音、知乎、快手、小紅書等各大平臺陸陸續續都上線了“網絡用戶IP地址顯示功能”,境外用戶顯示的是國家,國內的用戶顯示的省份,而且此項顯示無法關閉,歸屬地強制顯示。

作為技術人,那!這個功能要怎么實現呢?

1.HttpServletRequest 獲取 IP

下面,我就來講講,Java中是如何獲取IP屬地的,主要分為以下幾步:

  • 通過 HttpServletRequest 對象,獲取用戶的?「IP」?地址

  • 通過 IP 地址,獲取對應的省份、城市

首先需要寫一個 IP 獲取的工具類,因為每一次用戶的 Request 請求,都會攜帶上請求的 IP 地址放到請求頭中

import?javax.servlet.http.HttpServletRequest; import?java.net.InetAddress; import?java.net.NetworkInterface; import?java.net.UnknownHostException;/***?常用獲取客戶端信息的工具*/ public?class?NetworkUtil?{/***?獲取ip地址*/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.getHeader("HTTP_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".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為客戶端真實IP,多個IP按照','分割if?(null?!=?ip?&&?ip.length()?>?15)?{if?(ip.indexOf(",")?>?15)?{ip?=?ip.substring(0,?ip.indexOf(","));}}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();}}

通過此方法,從請求Header中獲取到用戶的IP地址。

之前我在做的項目中,也有獲取IP地址歸屬地省份、城市的需求,用的是:淘寶IP庫。

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

taobao的ip庫下線了

再見ip.taobao,全網顯示 IP 歸屬地。

ip歸屬地

原來的請求源碼如下:

可以看到日志log文件中,大量的the request over max qps for user問題。

留下了難過的淚水

2.Ip2region

下面,給大家介紹下之前在Github沖浪時發現的今天的主角:

Ip2region開源項目,github地址:https://github.com/lionsoul2014/ip2region。

?

目前最新已更新到了v2.0版本,ip2region v2.0是一個離線IP地址定位庫和IP定位數據管理框架,10微秒級別的查詢效率,準提供了眾多主流編程語言的 xdb 數據生成和查詢客戶端實現。

?
3.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將停止數據的更新服務。

4.多查詢客戶端的支持

已經集成的客戶端有:java、C#、php、c、python、nodejs、php擴展(php5和php7)、golang、rust、lua、lua_c, nginx。

binding描述開發狀態binary查詢耗時b-tree查詢耗時memory查詢耗時
cANSC c binding已完成0.0x毫秒0.0x毫秒0.00x毫秒
c#c# binding已完成0.x毫秒0.x毫秒0.1x毫秒
golanggolang 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.1x毫秒
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毫秒

5.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 中追加特定業務需求的數據,例如:GPS信息/國際統一地域信息編碼/郵編等。也就是你完全可以使用 ip2region 來管理你自己的 IP 定位數據。

    6.ip2region xdb java 查詢客戶端實現

    • 「使用方式」

    引入maven倉庫:

    <dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>2.6.4</version> </dependency>
    • 「完全基于文件的查詢」

    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 對象單獨使用。} }
    • 「緩存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 緩存。} }
    • 「緩存整個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 對象做成全局對象去跨線程訪問。} }

    7.IDEA中做個測試

    IDEA中做個測試

    完全基于文件的查詢

    ip屬地國內的話,會展示省份,國外的話,只會展示國家。可以通過如下圖這個方法進行進一步封裝,得到獲取IP屬地的信息。

    完全基于文件的查詢
    ?

    下面是官網給出的命令運行jar方式給出的測試demo,可以理解下

    ?

    8.編譯測試程序

    通過 maven 來編譯測試程序。

    #?cd?到?java?binding?的根目錄 cd?binding/java/ mvn?compile?package

    然后會在當前目錄的 target 目錄下得到一個 ip2region-{version}.jar 的打包文件。

    9.查詢測試

    可以通過 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 來測試三種不同緩存實現的查詢效果。

    10.bench 測試

    可以通過 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 文件相同的源文件。

    ?

    到這里獲取用戶IP屬地已經完成啦,這篇文章介紹的v2.0版本,有興趣的小伙伴可以登錄上門的github地址了解下v1.0版本

    ?

    如若覺得有用,歡迎收藏+點贊!

    來源:https://juejin.cn/post/7118954784853327903

    精彩推薦

    1.用 IDEA 基于SpringBoot2+ mybatis+Redis實現一個秒殺系統(附上源碼) 2.公司新來一個同事,把 @Transactional 事務注解運用得爐火純青。。2.Spring Batch 批處理框架,真的太強悍了!! 3.isEmpty 和 isBlank 請別亂用了,小心把服務器搞崩! 4.求求你別再自己瞎寫工具類了,Spring Boot 內置工具類涵蓋了所有操作! 5.新來的大佬一個注解搞定 Spring Boot 接口惡意刷新和暴力請求!又學會一招! 7.這是我見過寫得最爛的Controller層代碼,沒有之一! 8.3年工作經驗,多線程間的5種通信方式一個都答不上來,你敢信?

    總結

    以上是生活随笔為你收集整理的老板要我做一个 IP 属地功能,要求准确率99.9%!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。