前幾個月微信公眾號上線了IP歸屬地
的功能,後續知乎、抖音等平臺紛紛新增了該功能。如果是國內的使用者精確到省份,國外使用者精確到國家。本文就使用Java
實現獲取IP歸屬地
。
!
主要講解幾個步驟:
Java
獲取請求IP
Nginx
轉發問題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.1
的IP
。
所以需要部署到外網伺服器才能獲取到公網地址。部署到外網伺服器能成功獲取IP
地址。
直接存取公網伺服器地址能成功獲取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
獲取歸屬地一般都從地址庫找到匹配的地址,本文介紹兩種方法.
需要發起http
請求,這裡使用Spring Boot
的RestTemplate
發起http
請求,首先建立RestTemplate
的bean
範例:
@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
地址定位庫 Ip2region,Ip2region
是一個離線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|廣東省|廣州市|電信
。
根據上面的程式,做了一個小程式展示歸屬地。
頁面效果圖:
掃一掃,就能獲取查到自己的歸屬地了。