手把手教你用Java獲取IP歸屬地

來源: 手把手教你用Java獲取IP歸屬地

 

前幾個月微信公衆號上線了IP歸屬地的功能,後續知乎、抖音等平臺紛紛添加了該功能。如果是國內的用戶精確到省份,國外用戶精確到國家。本文就使用Java實現獲取IP歸屬地

主要講解幾個步驟:

  • Java獲取請求IP
  • 解決Nginx轉發問題
  • 通過IP地址獲取歸屬地

獲取IP地址

首先使用基於Spring Boot搭建項目,在controller添加HttpServletRequest請求參數:

@RestController
public class IpController {
    @GetMapping("/ip-address")
    public String ipAddress(HttpServletRequest request)  {
        // 接收request  
    }
}

通過HttpServletRequest獲取IP地址

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();
}
return ip;

在本地環境調用獲取IP,要麼是0:0:0:0:0:0:0:1,或者是局域網IP

局域網IP是以192.168.x.x開頭,或者是127.0.0.1IP

所以需要部署到外網服務器才能獲取到公網地址。部署到外網服務器能成功獲取IP地址。

Nginx 反向代理問題

直接訪問公網服務器地址能成功獲取IP地址,但是通過Nginx反向代理獲取的都是127.0.0.1。客戶端請求Nginx服務器再反向代理轉發到服務端,此時拿到的IP反向代理的IP,也就是Nginx服務器的IP,並不是真正的客戶端IP

Nginx的配置文件中的location模塊添加以下配置,將客戶端的IP傳入到Nginx服務:

proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

示例:

server {  
    listen 80;  
    server_name localhost;  
    location / { 
         proxy_set_header        X-Real-IP       $remote_addr;
         proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_pass http://xxxx;
    }

完成以上操作之後,就能成功獲取到IP了。然後通過IP獲取歸屬地了。

IP獲取歸屬地

通過IP獲取歸屬地一般都從地址庫找到匹配的地址,本文介紹兩種方法.

通過歸屬地API獲取

需要發起http請求,這裏使用Spring BootRestTemplate發起http請求,首先創建RestTemplatebean實例:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

再調用RestTemplate發起http請求:

private String URL = "https://api.beijinxuetang.com/api/common/ip";
JSONObject jsonObject = new JSONObject();
jsonObject.put("ip",ip);
JSONObject json = restTemplate.postForObject(URL,jsonObject, JSONObject.class);
if (json.getInteger("code") == 0) {
    json = json.getJSONObject("data");
    // 國家
    String nation = json.getString("nation");
    // 省份
    String province = json.getString("province");
    // 市
    String city = json.getString("city");
}
上面的json是引入fastjson

通過地址庫獲取

使用API接口,可能會出現服務掛了,或者服務地址不提供服務了等問題。而採用本地地址庫就沒有這些問題。

本文采用離線IP地址定位庫 Ip2regionIp2region是一個離線IP地址定位庫,微秒的查詢時間:

首先找到在gihub官網找到地址庫ip2region.xdb,具體路徑爲data/ip2region.xdb:

ip2region.xdb放在項目的resources目錄下:

引入maven依賴:

<dependency>
   <groupId>org.lionsoul</groupId>
   <artifactId>ip2region</artifactId>
   <version>2.6.5</version>
  </dependency>

獲取歸屬地:

private Searcher searcher;

@Override
    public String getIpAddress(String ip){
        if ("127.0.0.1".equals(ip) || ip.startsWith("192.168")) {
            return "局域網 ip";
        }
        if (searcher == null) {
            try {
                File file = ResourceUtils.getFile("classpath:ipdb/ip2region.xdb");
                String dbPath = file.getPath();
                searcher = Searcher.newWithFileOnly(dbPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        String region = null;
        String errorMessage = null;
        try {
            region = searcher.search(ip);
        } catch (Exception e) {
            errorMessage = e.getMessage();
            if (errorMessage != null && errorMessage.length() > 256) {
                errorMessage = errorMessage.substring(0,256);
            }
            e.printStackTrace();
        }
        // 輸出 region
    }

獲取region就能獲取到IP歸屬地了。例如中國|0|廣東省|廣州市|電信

小程序效果展示

根據上面的程序,做了一個小程序展示歸屬地。

頁面效果圖:

掃一掃,就能獲取查到自己的歸屬地了。

發佈於 2022-09-12 10:39
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章