全網都在顯示的IP歸屬地,5分鐘帶你加上,就這麼簡單
大家好,我是一航!
最近,繼新浪微博之後,今日頭條、騰訊、抖音、知乎、快手、小紅書、百家號等各大平臺陸陸續續都上線了" 網路使用者IP地址顯示功能",境外使用者顯示的是國家,國內的使用者顯示的省份,而且此項顯示無法關閉,歸屬地強制顯示;
作為技術人,那!這個功能要怎麼實現呢?
其實要想實現這個功能還是非常的容易,基於現成 GeoLite2離線庫+免費的線上解析資源,5分鐘就能整合了;
在整合之前,我們先簡單瞭解一下,要想拿到使用者的位置資訊,有那些方式:
-
終端定位
我們的手機等電子裝置都是帶有GPS定位功能的,APP可以申請許可權獲取使用者所處的經緯度座標,根據座標,就可以知道到使用者所處的位置;比如百度、高德等地圖廠商,就提供了完善的SDK,能非常方便的整合到應用,快速根據經緯度獲取詳細的位置詳細;
優點
-
快捷; -
準確; -
誤差小。
缺點
-
依賴硬體支援; -
依賴使用者授權,如果使用者不授權,APP將拿不到經緯度資訊,導致失敗;
-
-
IP地址獲取
使用者向服務端發起的請求都會帶上IP地址,服務端拿到IP地址後,就能基於IP解析出使用者的所處的位置;
優點
-
無需授權,只要使用者跟服務端互動,服務端就能拿到對應的IP資訊
缺點
-
準確性不高,位置可能存在偏差; -
IP庫更新不及時,導致部分IP歸屬地解析失敗。
-
-
三方終端上報
比如,我們騎共享單車的時候,我們的位置資訊就是透過單車的裝置上報到伺服器;
優點
-
由三方終端基於GPS定位上報,不會獲取個人裝置的資訊; -
準確快捷; -
專業裝置,誤差小;
缺點
-
使用者無法干預,資訊會被迫強制上傳至服務端,使用者無法取消上傳;
-
下面就來試著將 GeoLite2 免費 IP 庫整合值SpringBoot專案,來獲取使用者的歸屬地資訊;
什麼是GeoLite2?
GeoLite2資料庫是免費的IP地理定位資料庫;
優點:
-
離線庫,不需要網路 -
資料庫豐富 -
速度快 -
免費
缺點:
-
準確度不高,存在偏差 -
資料更新慢
下載 GeoLite2 離線庫
官網地址:
下載過程稍微有點點麻煩,這裡下載了一份最新的,放在網盤,需要測試的可以直接透過這個連結下載:
SpringBoot 獲取使用者的IP
-
工具類
public class IpUtils {
/**
* 獲取使用者IP
* @param request
* @return
*/
public static String getIpAddr (HttpServletRequest request) {
String ip = request.getHeader( "x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader( "X-Real-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.getRemoteAddr();
}
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_X_FORWARDED_FOR");
}
// 如果是多級代理,那麼取第一個ip為客戶ip
if (ip != null && ip.indexOf( ",") != - 1) {
ip = ip.substring(ip.lastIndexOf( ",") + 1).trim();
}
return ip;
}
} -
Controller獲取HttpServletRequest
透過上面的工具類,即可獲取使用者請求的真實IP;
為了避免重複工作,這裡也可以使用AOP解析出使用者的IP資訊,放到使用者的請求物件中
@RestController
public class IpController {
@GetMapping( "/user/ip")
public String userIp (HttpServletRequest request) {
// 這裡就能拿到使用者的真實IP
return IpUtils.getIpAddr(request);
}
}
SpringBoot 整合 GeoLite2
-
新增依賴
< dependency>
< groupId>com.maxmind.geoip2 </ groupId>
< artifactId>geoip2 </ artifactId>
< version>2.3.0 </ version>
</ dependency>
< dependency>
< groupId>com.maxmind.db </ groupId>
< artifactId>maxmind-db </ artifactId>
< version>1.0.0 </ version>
</ dependency> -
工具類
public class GeoIpUtils {
private static DatabaseReader reader;
private static void init () {
try {
// 建立 GeoLite2 資料庫 Reader
// 這裡可以放在本地磁碟,也可以隨專案放在resource目錄下
File database = new File( "F:\\web\\GeoLite2-City.mmdb");
// 讀取資料庫內容
reader = new DatabaseReader.Builder(database).build();
} catch (Exception ex) {
}
}
public static void getCityByIP (String ip) throws Exception {
if ( null == reader) {
init();
}
InetAddress ipAddress = InetAddress.getByName(ip);
// 獲取查詢結果
CityResponse response = reader.city(ipAddress);
// 獲取國家資訊
Country country = response.getCountry();
System.out.println( "國家資訊:" + JSON.toJSONString(country));
// 獲取省份
Subdivision subdivision = response.getMostSpecificSubdivision();
System.out.println( "省份資訊:" + JSON.toJSONString(subdivision));
//城市
City city = response.getCity();
System.out.println( "城市資訊:" + JSON.toJSONString(city));
// 獲取城市
Location location = response.getLocation();
System.out.println( "經緯度資訊:" + JSON.toJSONString(location));
}
} -
測試
public static void main (String[] args) throws Exception {
String ip = "183.19.xxx.138";
GeoIpUtils.getCityByIP(ip);
}輸出結果:
國家資訊:{ "geoNameId": 1814991, "isoCode": "CN", "name": "China", "names":{ "de": "China", "ru": "Китай", "pt-BR": "China", "ja": "中國", "en": "China", "fr": "Chine", "zh-CN": "中國", "es": "China"}}
省份資訊:{ "geoNameId": 1809935, "isoCode": "GD", "name": "Guangdong", "names":{ "en": "Guangdong", "fr": "Province de Guangdong", "zh-CN": "廣東"}}
城市資訊:{ "geoNameId": 1998011, "name": "Yanqianlaocun", "names":{ "en": "Yanqianlaocun", "zh-CN": "巖前老村"}}
經緯度資訊:{ "accuracyRadius": 500, "latitude": 23.3255, "longitude": 116.5007, "timeZone": "Asia/Shanghai"}
就這麼簡單,輕輕鬆鬆就能拿到使用者IP所處的國家、省份、城市、經緯度等詳細資訊,可以根據自己的業務需要,對這些資料再做進一步的封裝。
GeoLite2的其他用法
上面介紹的時SpringBoot整合GeoLite2,同樣在其他的一些場景下,也是可以利用GeoLite2獲取歸屬地資訊;
-
整合至Nignx,獲取使用者歸屬地資訊
Nginx 整合 GeoLite2 來解析使用者的歸屬地資訊,在代理層就直接整理好對應的資料;
-
ELK中整合GeoLite2
ELK 日誌整理的時候,可以透過GeoLite2 獲取使用者的IP歸屬地資訊;然後透過Kibana,就能非常直觀的展示使用者的地域分佈情況;
線上方案
上面一開始介紹GeoLite2時就列舉了其離線庫更新收錄不及時的問題,可能導致一些IP在離線庫中並不存在,查詢的時候,就會報
AddressNotFoundException
的錯誤,如下示例:
遇到這種請求,我們要怎麼辦呢?
下面就來介紹幾種線上IP歸屬地獲取的方式,當本地離線庫無法獲取的時候,就可以利用三方的線上庫,來補充完善;
線上獲取的優點:
-
IP更新及時 -
準確度高
缺點
-
三方依賴性強 -
需要付費,免費版本一般都有各種限制
以下示例中的xxx.xxx.xxx.xxx均代表ip地址;
百度
地址:
響應資料:
{
"status":
"0",
"t":
"",
"set_cache_time":
"",
"data": [
{
"ExtendedLocation":
"",
"OriginQuery":
"183.19.xxx.138",
"appinfo":
"",
"disp_type":
0,
"fetchkey":
"183.19.xxx.138",
"location":
"廣東省肇慶市 電信",
"origip":
"183.19.xxx.138",
"origipquery":
"183.19.xxx.138",
"resourceid":
"6006",
"role_id":
0,
"shareImage":
1,
"showLikeShare":
1,
"showlamp":
"1",
"titlecont":
"IP地址查詢",
"tplt":
"ip"
}
]
}
status等於0表示成功,1表示失敗;可能存在status等於0,但是data中沒有資料的情況。
ip-api介面
-
本機的IP資訊
-
指定國際化
?lang=zh-CN
-
指定IP查詢
xxx.xxx.xxx.xxx?lang=zh-CN
返回資料:
{
"status": "success",
"country": "中國",
"countryCode": "CN",
"region": "GD",
"regionName": "廣東",
"city": "巖前老村",
"zip": "",
"lat": 23.3255,
"lon": 116.5007,
"timezone": "Asia/Shanghai",
"isp": "Chinanet",
"org": "Chinanet GD",
"as": "AS4134 CHINANET-BACKBONE",
"query": "183.19.xxx.138"
}
搜狐IP查詢
返回資料比較的簡單:
var returnCitySN = {
"cip":
"xxx.xxx.xxx.xxx",
"cid":
"440300",
"cname":
"廣東省深圳市"};
太平洋IP地址查詢
地址:
返回資料:
{
"ip":
"183.17.xxx.138",
"pro":
"廣東省",
"proCode":
"440000",
"city":
"深圳市",
"cityCode":
"440300",
"region":
"",
"regionCode":
"0",
"addr":
"廣東省深圳市 電信",
"regionNames":
"",
"err":
""
}
淘寶API介面
{
"code":
0,
"data": {
"ip":
"183.17.xxx.138",
"country":
"中國",
"area":
"",
"region":
"廣東",
"city":
"深圳",
"county":
"XX",
"isp":
"電信"
}
}
code等於0表示成功,1表示失敗
126
地址:
響應資料:
var lo=
"廣東省", lc=
"肇慶市";
var localAddress={
city:
"肇慶市",
province:
"廣東省"}
響應的資料比較的簡單
IP資訊
地址:
響應資料:
{
"country":
"中國",
"short_name":
"CN",
"province":
"廣東省",
"city":
"肇慶市",
"area":
"德慶縣",
"isp":
"電信",
"net":
"",
"ip":
"183.19.xxx.138",
"code":
200,
"desc":
"success"
}
這麼多的姿勢,實現起來是不是就非常的容易了;如果你對IP解析的需求比較依賴,也完全可以透過離線加這麼多線上的方式,開發一個單獨的IP解析模組,作為公司的基礎服務,提供給內部其他模組使用。
好了,今天的分享就到這裡,感謝你的點贊、關注、收藏!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70035356/viewspace-2996036/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一文帶你看透IP歸屬地
- 歸併排序就這麼簡單排序
- Elasticsearch就這麼簡單Elasticsearch
- 如何快速查詢IP歸屬地
- 堆排序就這麼簡單排序
- 快速排序就這麼簡單排序
- 泛型就這麼簡單泛型
- 各精度最全最好用的IP歸屬地APIAPI
- IP歸屬地的應用場景有哪些?
- 簡單幾步讓你的Excel表格變漂亮,學會Excel就這麼簡單!Excel
- 基於 ip2region 使用 go 擴充套件的一個簡單的 IP 地址歸屬地查詢服務Go套件
- 氣泡排序就這麼簡單排序
- 基數排序就這麼簡單排序
- 插入排序就這麼簡單排序
- 選擇排序就這麼簡單排序
- cocos-lua 獲取IP 歸屬地
- 策略模式原來就這麼簡單!模式
- SpringDataJPA入門就這麼簡單Spring
- SpringMVC入門就這麼簡單SpringMVC
- TreeMap就這麼簡單【原始碼剖析】原始碼
- 國內部分手機遊戲開始顯示使用者IP屬地遊戲
- 網站能通過IP訪問,域名加上cdn後顯示響應時間過長怎麼辦?網站
- 使用 Redis 有序集合實現 IP 歸屬地查詢Redis
- LinkedHashMap就這麼簡單【原始碼剖析】HashMap原始碼
- List集合就這麼簡單【原始碼剖析】原始碼
- std list/vector sort 排序就這麼簡單排序
- 【計算機網路原理——愛你這麼簡單】計算機網路
- 成為圖靈的譯者就這麼簡單!圖靈
- [微博活動]《Wireshark網路分析就這麼簡單》轉發贈書
- Java實現一個棧就這麼簡單Java
- zookeeper核心之ZAB協議就這麼簡單!協議
- 讀懂IL程式碼就這麼簡單 (一)
- 發現了嗎?發表網路動態公開顯示“IP屬地”,會暴露我的行蹤隱私嗎?
- 原來寫個Vue 首頁就這麼簡單Vue
- python 多執行緒就這麼簡單(續)Python執行緒
- 處理 EF 併發其實就這麼簡單
- 如何不顯示地圖就獲取位置資料?地圖
- IP查詢類API介面查詢,含各精度IP歸屬地查詢介面API