java?IP歸屬地功能實(shí)現(xiàn)詳解
第一步:如何拿到用戶的真實(shí)IP
大家都知道,我們一般想訪問公網(wǎng),一般必須具備上網(wǎng)環(huán)境,那么我們開通寬帶之后,運(yùn)營(yíng)商會(huì)給我們分配一個(gè)IP地址。一般IP地址我們都是自動(dòng)分配的。所以我們不知道本機(jī)地址是什么?想知道自己的ip公網(wǎng)地址,可以通過百度搜索IP查看自己的ip位置
那么問題來了。百度是怎么知道我的公網(wǎng)IP的?
一般情況,用戶訪問我們的服務(wù)網(wǎng)絡(luò)拓?fù)淙缦拢?/p>
用戶通過域名或者IP訪問門戶,然后請(qǐng)求到后端服務(wù)。這樣的話后端服務(wù)就可以通過request.getRemoteAddr();方法獲取用戶的ip。
SpringBoot獲取IP如下:
@RestController public class IpController { @RequestMapping("/getIp") public String hello(HttpServletRequest request) { String ip = request.getRemoteAddr(); System.out.println(ip); return ip; } }
將服務(wù)部署到服務(wù)端,然后請(qǐng)求該接口,即可獲取IP信息,如下圖:
但是為什么我們獲取的IP和百度搜出來的不一樣呢?
1.1內(nèi)網(wǎng)IP和外網(wǎng)IP
打開電腦CMD,輸出ipconfig命令,查看本機(jī)的IP地址,發(fā)現(xiàn)我們本機(jī)地址和程序獲取的地址是一樣的。
其實(shí),網(wǎng)絡(luò)也是分內(nèi)網(wǎng)IP和公網(wǎng)IP的。內(nèi)網(wǎng)也成局域網(wǎng)。對(duì)于像公司,學(xué)校這種一般內(nèi)部建立自己的局域網(wǎng),對(duì)內(nèi)部的信息進(jìn)行傳輸時(shí),都是通過內(nèi)網(wǎng)相互通訊,建立局域網(wǎng)內(nèi)網(wǎng)通訊節(jié)省了公網(wǎng)IP資源,并且通信效率也有很大的提升。當(dāng)然非局域網(wǎng)內(nèi)的設(shè)備則無法向內(nèi)網(wǎng)的設(shè)備發(fā)送信息。
但是機(jī)器想要訪問互聯(lián)網(wǎng)的資源時(shí),則需要機(jī)器擁有外網(wǎng)帶寬,也就是我們所說的分配公網(wǎng)IP,負(fù)責(zé)也是無法訪問互聯(lián)網(wǎng)資源的。
因此,我們把服務(wù)部署在同一局域網(wǎng)內(nèi),客戶端使用內(nèi)網(wǎng)進(jìn)行通信,因此獲取的就是內(nèi)網(wǎng)IP地址。但訪問百度是需要使用公網(wǎng)訪問,因此百度搜出來的IP就是公網(wǎng)IP地址。
1.2.為什么有時(shí)候獲取到的客戶端IP有問題?
當(dāng)我們興致勃勃的把IP獲取的功能搞上去之后,發(fā)現(xiàn)獲取的IP都是同一個(gè)?這是為什么呢?不可能只是一個(gè)用戶在訪問呀?查詢IP信息之后發(fā)現(xiàn),原來是我們部署的一臺(tái)負(fù)載均衡的IP地址。
那么后端服務(wù)獲取的地址都是負(fù)載均衡如nginx的地址。那么怎么透過負(fù)載均衡獲取真實(shí)的地址呢?
透明的代理服務(wù)器在將客戶端的訪問請(qǐng)求轉(zhuǎn)發(fā)到下一環(huán)節(jié)的服務(wù)器時(shí),會(huì)在HTTP的請(qǐng)求頭中添加一條X-Forwarded-For記錄,用于記錄客戶端的IP,格式為X-Forwarded-For:客戶端IP。如果客戶端和服務(wù)器之間有多個(gè)代理服務(wù)器,則X-Forwarded-For記錄使用以下格式記錄客戶端IP和依次經(jīng)過的代理服務(wù)器IP:X-Forwarded-For:客戶端IP, 代理服務(wù)器1的IP, 代理服務(wù)器2的IP, 代理服務(wù)器3的IP, ……。
因此,常見的Web應(yīng)用服務(wù)器可以通過解析X-Forwarded-For記錄獲取客戶端真實(shí)IP。
public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } else if (ip.length() > 15) { //多次反向代理后會(huì)有多個(gè)ip值,第一個(gè)ip才是真實(shí)ip String[] ips = ip.split(","); for (int index = 0; index < ips.length; index++) { String strIp = ips[index]; ip = strIp; break; } } return ip; }
第二步:如何解析IP
IP來了,我們?cè)趺唇馕瞿兀?/p>
IP的解析一般都要借助第三方軟件使用了,第三方一般也分為離線庫(kù)和在線庫(kù)
- 離線庫(kù)支持的有如:IPIP,使用離線庫(kù)的好處是解析效率高,性能好,問題就是IP庫(kù)要經(jīng)常更新。如果大家需要我私信我可以提供給大家比較新版本的ip庫(kù)。
- 在線庫(kù)則各大云廠商接口能力都有支持。在線版本的好處是更新即時(shí),問題就是接口查詢性能和使用TPS有要求。
以下演示借助IP庫(kù)離線IP解析方式:
借助IP庫(kù)就可以幫我們實(shí)現(xiàn)ip地址的解析。
public static void main(String[] args) { IpAddrInfo IpAddrInfo = IPAddr.getInstance().putLocInfo("114.103.71.226"); System.out.println(JSONObject.toJSONString(IpAddrInfo)); } public IpAddrInfo putLocInfo(String ip) { IpAddrInfo info = new IpAddrInfo(); if (StringUtils.isNotBlank(ip)) { try { DistrictInfo addrInfo = db.findInfo(ip, "CN"); info.setCity(addrInfo.getCityName()); info.setCountry(addrInfo.getCountryName()); info.setCountryCode(addrInfo.getChinaAdminCode()); info.setIsp(addrInfo.getIsp()); info.setLat(addrInfo.getLatitude()); info.setLon(addrInfo.getLongitude()); info.setProvince(addrInfo.getRegionName()); info.setTimeZone(addrInfo.getTimeZone()); System.out.println(addrInfo.toString()); } catch (IPFormatException e) { e.printStackTrace(); } catch (InvalidDatabaseException e) { e.printStackTrace(); } } return info; }
其實(shí)IP的定位解析其實(shí)就是一個(gè)巨大的位置庫(kù),同時(shí)IP數(shù)量也是有限制的,因此同一個(gè)Ip也可能會(huì)分配到不同的區(qū)域,因此影響IP解析位置準(zhǔn)確率的有幾個(gè)方面
1、位置庫(kù)不精準(zhǔn),導(dǎo)致解析偏差大或者地區(qū)字段確實(shí)
2、離線庫(kù)更新不及時(shí) 并且海外的一般有專門的離線庫(kù)去支持,使用同一套離線庫(kù)并不一定支持海外IP的解析,所以本次受影響最大的海外網(wǎng)紅門被解析到中國(guó)各個(gè)地區(qū),被大家認(rèn)為造假,當(dāng)然也包括真的有造假。
不過上線了這個(gè)功能也是有好處的,至少網(wǎng)絡(luò)不是法外之地,大家也要有序的健康的沖浪,拒絕網(wǎng)絡(luò)暴力。
以上就是java IP歸屬地功能實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于java IP歸屬地的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java判斷List中相同值元素的個(gè)數(shù)實(shí)例
今天小編就為大家分享一篇Java判斷List中相同值元素的個(gè)數(shù)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07避免多個(gè)jar通過maven打包導(dǎo)致同名配置文件覆蓋沖突問題
這篇文章主要介紹了避免多個(gè)jar通過maven打包導(dǎo)致同名配置文件覆蓋沖突問題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Java的編譯時(shí)錯(cuò)誤和運(yùn)行時(shí)錯(cuò)誤問題
這篇文章主要介紹了Java的編譯時(shí)錯(cuò)誤和運(yùn)行時(shí)錯(cuò)誤問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04Springboot整合freemarker 404問題解決方案
這篇文章主要介紹了Springboot整合freemarker 404問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Spring security用戶URL權(quán)限FilterSecurityInterceptor使用解析
這篇文章主要介紹了Spring security用戶URL權(quán)限FilterSecurityInterceptor使用解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12MyBatis的@SelectProvider注解構(gòu)建動(dòng)態(tài)SQL方式
這篇文章主要介紹了MyBatis的@SelectProvider注解構(gòu)建動(dòng)態(tài)SQL方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08