• 手把手教你用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  
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在本地环境调用获取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;
    
    • 1
    • 2

    示例:

    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    完成以上操作之后,就能成功获取到IP了。然后通过IP获取归属地了。

    IP获取归属地

    通过IP获取归属地一般都从地址库找到匹配的地址,本文介绍两种方法.

    通过归属地API获取

    需要发起http请求,这里使用Spring BootRestTemplate发起http请求,首先创建RestTemplatebean实例:

    @Configuration
    public class RestTemplateConfig {
    
        @Bean
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    再调用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");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上面的json是引入fastjson

    通过地址库获取

    使用API接口,可能会出现服务挂了,或者服务地址不提供服务了等问题。而采用本地地址库就没有这些问题。

    本文采用离线IP地址定位库 Ip2regionIp2region是一个离线IP地址定位库,微秒的查询时间:

    首先找到在gihub官网找到地址库ip2region.xdb,具体路径为data/ip2region.xdb:

    ip2region.xdb放在项目的resources目录下:

    引入maven依赖:

    
    			org.lionsoul
    			ip2region
    			2.6.5
    		
    
    • 1
    • 2
    • 3
    • 4
    • 5

    获取归属地:

    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
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    获取region就能获取到IP归属地了。例如中国|0|广东省|广州市|电信

    小程序效果展示

    根据上面的程序,做了一个小程序展示归属地。

    页面效果图:

    扫一扫,就能获取查到自己的归属地了。

  • 相关阅读:
    c语言:通讯录管理系统(动态分配内存版)
    C语言_断言assert详解
    企业使用CRM会获得什么成效?
    npm install 报错 ‘proxy‘ config is set properly. See: ‘npm help config‘
    数据库扫描工具scuba
    QT 搭建FFmpeg环境
    算法3:链表实现队列
    C++使用两个栈实现双端队列——F1 B1 B2 B3 B4 B5 PF PF PB PB
    云计算基础技术
    章节十六:复习与反爬虫
  • 原文地址:https://blog.csdn.net/qq_42700121/article/details/126811143