前一陣鬧得沸沸揚揚的IP歸屬地,到底是怎麼實現的?

語言: CN / TW / HK

大家好,我是王老師,一直在準備寫這篇稿子,但是事情太多一直耽誤了,導致一直拖一直拖,結果就從最近變成了前一陣子。這下好了,不會有人說我蹭熱度了。

image.png

image.png

大家都知道,前一陣子抖音和微博開始陸續上了IP歸屬地的功能,引起了眾多熱議。有大批在國外的老鐵們開始"原形畢露",被定位到國內來,那麼IP歸屬到底是怎麼實現的呢?那麼網紅們的歸屬地到底對不對呢?這篇文章幫大家揭曉。

一.第一步:如何拿到使用者的真實IP

大家都知道,我們一般想訪問公網,一般必須具備上網環境,那麼我們開通寬頻之後,運營商會給我們分配一個IP地址。一般IP地址我們都是自動分配的。所以我們不知道本機地址是什麼?想知道自己的ip公網地址,可以通過百度搜索IP檢視自己的ip位置 image.png

那麼問題來了。百度是怎麼知道我的公網IP的?

一般情況,使用者訪問我們的服務網路拓撲如下:

image.png

使用者通過域名或者IP訪問門戶,然後請求到後端服務。這樣的話後端服務就可以通過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;   } }

將服務部署到服務端,然後請求該介面,即可獲取IP資訊,如下圖:

image.png

但是為什麼我們獲取的IP和百度搜出來的不一樣呢?

1.1內網IP和外網IP

開啟電腦CMD,輸出ipconfig命令,檢視本機的IP地址,發現我們本機地址和程式獲取的地址是一樣的。

image.png

其實,網路也是分內網IP和公網IP的。內網也成區域網。對於像公司,學校這種一般內部建立自己的區域網,對內部的資訊進行傳輸時,都是通過內網相互通訊,建立區域網內網通訊節省了公網IP資源,並且通訊效率也有很大的提升。當然非區域網內的裝置則無法向內網的裝置傳送資訊。

但是機器想要訪問網際網路的資源時,則需要機器擁有外網頻寬,也就是我們所說的分配公網IP,負責也是無法訪問網際網路資源的。

image.png

因此,我們把服務部署在同一區域網內,客戶端使用內網進行通訊,因此獲取的就是內網IP地址。但訪問百度是需要使用公網訪問,因此百度搜出來的IP就是公網IP地址。

1.2.為什麼有時候獲取到的客戶端IP有問題?

當我們興致勃勃的把IP獲取的功能搞上去之後,發現獲取的IP都是同一個?這是為什麼呢?不可能只是一個使用者在訪問呀?查詢IP資訊之後發現,原來是我們部署的一臺負載均衡的IP地址。

image.png

那麼後端服務獲取的地址都是負載均衡如nginx的地址。那麼怎麼透過負載均衡獲取真實的地址呢?

透明的代理伺服器在將客戶端的訪問請求轉發到下一環節的伺服器時,會在HTTP的請求頭中新增一條X-Forwarded-For記錄,用於記錄客戶端的IP,格式為X-Forwarded-For:客戶端IP。如果客戶端和伺服器之間有多個代理伺服器,則X-Forwarded-For記錄使用以下格式記錄客戶端IP和依次經過的代理伺服器IP:X-Forwarded-For:客戶端IP, 代理伺服器1的IP, 代理伺服器2的IP, 代理伺服器3的IP, ……

因此,常見的Web應用伺服器可以通過解析X-Forwarded-For記錄獲取客戶端真實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) {       //多次反向代理後會有多個ip值,第一個ip才是真實ip       String[] ips = ip.split(",");       for (int index = 0; index < ips.length; index++) {           String strIp = ips[index];           ip = strIp;           break;       }   }   return ip; }

第二步:如何解析IP

IP來了,我們怎麼解析呢:

IP的解析一般都要藉助第三方軟體使用了,第三方一般也分為離線庫和線上庫

  • 離線庫支援的有如:IPIP,使用離線庫的好處是解析效率高,效能好,問題就是IP庫要經常更新。如果大家需要我私信我可以提供給大家比較新版本的ip庫。
  • 線上庫則各大雲廠商介面能力都有支援。線上版本的好處是更新即時,問題就是介面查詢效能和使用TPS有要求。

以下演示藉助IP庫離線IP解析方式:

藉助IP庫就可以幫我們實現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; }

image.png

其實IP的定位解析其實就是一個巨大的位置庫,同時IP數量也是有限制的,因此同一個Ip也可能會分配到不同的區域,因此影響IP解析位置準確率的有幾個方面 1、位置庫不精準,導致解析偏差大或者地區欄位確實 2、離線庫更新不及時 並且海外的一般有專門的離線庫去支援,使用同一套離線庫並不一定支援海外IP的解析,所以本次受影響最大的海外網紅門被解析到中國各個地區,被大家認為造假,當然也包括真的有造假。不過上線了這個功能也是有好處的,至少網路不是法外之地,大家也要有序的健康的衝浪,拒絕網路暴力。

好了,今天就到這裡,我是王老獅,一個有想法有內涵的工程獅,關注我,學習更多技術知識。