前几个月微信公众号上线了 IP归属地 的功能,后续知乎、抖音等平台纷纷添加了该功能。如果是国内的用户精确到省份,国外用户精确到国家。本文就使用 Java 实现获取 IP归属地

主要讲解几个步骤:

Java 获取请求 IP解决 Nginx 转发问题通过 IP 地址获取归属地

获取IP地址

首先使用基于 Spring Boot搭建项目,在controller 添加 HttpServletRequest 请求参数:

@RestControllerpublic 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 实例:

@Configurationpublic class RestTemplateConfig {@Beanpublic RestTemplate restTemplate() {return newRestTemplate();}}

再调用 RestTemplate 发起 http 请求:

private String URL = "https://api.beijinxuetang.com/api/common/ip";JSONObject jsonObject = newJSONObject();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");// 市Stringcity = 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;@Overridepublic 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|广东省|广州市|电信

分类: 百科知识 标签: 暂无标签

评论

暂无评论数据

暂无评论数据

目录