通过 Request 请求获取真实 IP 地址以及对应省份城市

这篇具有很好参考价值的文章主要介绍了通过 Request 请求获取真实 IP 地址以及对应省份城市。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


title: 通过 Request 请求获取真实 IP 地址以及对应省份城市和系统浏览器信息
date: 2022-12-16 16:20:26
tags:

  • GeoIP2
  • UserAgentUtils
    categories:
  • 开发实践
    cover: https://cover.png
    feature: false

1. 获取真实 IP 地址

1.1 代码

代码如下,这里的 CommonUtil.isBlank() 为封装的判空方法

public static String getIpAddress(HttpServletRequest request) {
        // 首先, 获取 X-Forwarded-For 中的 IP 地址,它在 HTTP 扩展协议中能表示真实的客户端 IP
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (CommonUtil.isNotBlank(ipAddress) && !"unknown".equalsIgnoreCase(ipAddress)) {
            // 多次反向代理后会有多个 ip 值,第一个 ip 才是真实 ip, 例: X-Forwarded-For: client, proxy1, proxy2,proxy…
            int index = ipAddress.indexOf(",");
            if (index != -1) {
                return ipAddress.substring(0, index);
            }

            return ipAddress;
        }

        // 如果 X-Forwarded-For 获取不到, 就去获取 X-Real-IP
        ipAddress = request.getHeader("X-Real-IP");
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 X-Real-IP 获取不到, 就去获取 Proxy-Client-IP
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 Proxy-Client-IP 获取不到, 就去获取 WL-Proxy-Client-IP
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 WL-Proxy-Client-IP 获取不到, 就去获取 HTTP_CLIENT_IP
            ipAddress = request.getHeader("HTTP_CLIENT_IP");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 HTTP_CLIENT_IP 获取不到, 就去获取 HTTP_X_FORWARDED_FOR
            ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 都获取不到, 最后才通过 request.getRemoteAddr() 获取IP
            ipAddress = request.getRemoteAddr();
        }

        return "0:0:0:0:0:0:0:1".equals(ipAddress) ? "127.0.0.1" : ipAddress;;
}

1.2 解释

1、首先,获取 X-Forwarded-For 中第 0 位的 IP 地址,它在 HTTP 扩展协议中能表示真实的客户端 IP,如下例:

X-Forwarded-For: client, proxy1, proxy2, proxy…

2、如果 X-Forwarded-For 获取不到,就去获取 X-Real-IPX-Real-IP 获取不到,就依次获取 Proxy-Client-IPWL-Proxy-Client-IPHTTP_CLIENT_IPHTTP_X_FORWARDED_FOR 。最后获取不到才通过 request.getRemoteAddr() 获取 IP

  1. X-Real-IP 记录请求的客户端真实 IP,与 X-Forwarded-For 类似
  2. Proxy-Client-IP 代理客户端的 IP,如果客户端真实 IP 获取不到的时候,就只能获取代理客户端的 IP 了
  3. WL-Proxy-Client-IP 在 Weblogic 下获取真实 IP 所用的的参数
  4. HTTP_CLIENT_IPHTTP_X_FORWARDED_FOR 可以理解为 X-Forwarded-For , 它们是 PHP 中的用法

3、在服务器上通过 request.getRemoteAddr() 获取服务器的地址时,获取到的是 IPV6 的 0:0:0:0:0:0:0:1,需要转换为 IPV4 的 127.0.0.1

1.3 Nginx 配置请求头参数

server {
        listen       8081;
        server_name  localhost;

        location / {
            root   html/resource-nav;
            index  index.html index.htm;
        }
  
        location ~ /resNav {
            #代理请求头相关
	    proxy_set_header Host $host:$server_port; 
	    proxy_set_header X-Real-Ip $remote_addr;
	    proxy_set_header X-Forwarded-For $remote_addr;
  
            proxy_pass http://ip:port;
        }
}

2. 通过 IP 地址获取省份城市信息

分为两种方式,在线和离线:

1、使用在线第三方提供的 api:

  • ip-api.com
  • ip.taotao.com
  • 百度地图 api
  • 新浪 iplookup

2、使用离线查询方式:

  • 纯真库
  • GeoLite2
  • 埃文科技

具体的数据丰富性、准确性和查询速度可自行搜集相关资料。由于 GeoLite2 免费,且离线查询速度更快和稳定,同时不限制 API 并发数等,这里使用 GeoLite2 来获取省份城市信息,同时数据丰富性也比较高

2.1 下载 GeoLite2 City 库

GeoLite 数据库是 MaxMind 公司旗下的 ,GeoLite 数据库有开源版本和收费版本,这里使用开源版本,GeoLite 目前已经更新到 2 了,所以下载 GeoLite2 City 库。下载地址如下:GeoLite2 Free Geolocation Data | MaxMind Developer Portal

点击页面中的 Download Files

request获取ip,开发实践,tcp/ip,网络,服务器

未登录的话会跳转到登录页面

request获取ip,开发实践,tcp/ip,网络,服务器

没有账户的话点击创建

request获取ip,开发实践,tcp/ip,网络,服务器

这里会有几种账户形式,选择登录免费的 GeoLite2 数据库和 Web 服务

request获取ip,开发实践,tcp/ip,网络,服务器

填写完对应的信息后,会发一封设置密码的邮件,点击链接设置密码

request获取ip,开发实践,tcp/ip,网络,服务器

完成后点击进行登录

request获取ip,开发实践,tcp/ip,网络,服务器

输入用户名密码进行登录,用户名就是邮箱地址

request获取ip,开发实践,tcp/ip,网络,服务器

选择下载数据库

request获取ip,开发实践,tcp/ip,网络,服务器

选择 GZIP 下载

request获取ip,开发实践,tcp/ip,网络,服务器

下载完成后会得到一个 tar 包文件

request获取ip,开发实践,tcp/ip,网络,服务器

解压后里面就是我们需要的数据库文件(Windows 可用 7-Zip 解压)

request获取ip,开发实践,tcp/ip,网络,服务器

2.2 使用

2.2.1将文件放入项目根路径下

request获取ip,开发实践,tcp/ip,网络,服务器

2.2.2 引入依赖

好像 3.0 版本以上最低支持 JDK 11,假如是 JDK 8 的话最高使用 2.16.1 即可

<!-- GeoIP2 -->
<dependency>
        <groupId>com.maxmind.geoip2</groupId>
        <artifactId>geoip2</artifactId>
        <version>2.16.1</version>
</dependency>

2.2.3 代码

这里的 new DatabaseReader.Builder(database).build() 支持两种类型,一种是 File,一种是 InputStream。本地项目两种皆可,但打包到服务器上运行时获取 File 类型文件可能会存在问题,最好通过流的方式来获取构建

public class Test {
    public static void main(String[] args) throws IOException, GeoIp2Exception {
        // 读取数据库文件
        ClassPathResource classPathResource = new ClassPathResource("GeoLite2-City.mmdb");
        InputStream database = database = classPathResource.getInputStream();
        // 创建数据库
        DatabaseReader reader = new DatabaseReader.Builder(database).build();
        // 获取 IP 地址信息
        InetAddress ipAddress = InetAddress.getByName("139.227.47.35");

        // 获取查询信息
        CityResponse response = reader.city(ipAddress);

        // 国家信息
        Country country = response.getCountry();
        System.out.println(country.getIsoCode()); // 'CN'
        System.out.println(country.getName()); // 'China'
        // {de=China, ru=Китай, pt-BR=China, ja=中国, en=China, fr=Chine, zh-CN=中国, es=China}
        System.out.println(country.getNames());
        System.out.println(country.getNames().get("zh-CN")); // '中国'

        // 省级信息
        Subdivision subdivision = response.getMostSpecificSubdivision();
        System.out.println(subdivision.getIsoCode()); // 'SH'
        System.out.println(subdivision.getName()); // 'Shanghai'
        // {{en=Shanghai, fr=Municipalité de Shanghai, zh-CN=上海, pt-BR=Xangai}}
        System.out.println(subdivision.getNames());
        System.out.println(subdivision.getNames().get("zh-CN")); // '上海'

        // 城市信息
        City city = response.getCity();
        System.out.println(city.getName()); // 'Shanghai'
        System.out.println(city.getNames().get("zh-CN")); // '上海'

        // 邮政编码(国内的可能获取不到)
        Postal postal = response.getPostal();
        System.out.println(postal.getCode()); // '55423'

        // 经纬度
        Location location = response.getLocation();
        System.out.println(location.getLatitude()); // 纬度 31.2222
        System.out.println(location.getLongitude()); // 经度 121.4581
    }
}

request获取ip,开发实践,tcp/ip,网络,服务器

2.3 封装成工具类

1、实体类

@Data
@TableName("login_geo")
public class LoginGeoDO {

    // 主键ID
    private String id;

    // 国家 ISO 代码
    private String countryIsoCode;

    // 国家名称
    private String countryName;

    // 国家中文名称
    private String countryZhCnName;

    // 省级 ISO 代码, 外国则是同级别地区代码
    private String subdivisionIsoCode;

    // 省级名称
    private String subdivisionName;

    // 省级中文名称
    private String subdivisionZhCnName;

    // 城市名称
    private String cityName;

    // 城市中文名称
    private String cityZhCnName;

    // 邮政编码
    private String postal;

    // 纬度
    private double latitude;

    // 经度
    private double longitude;

    // 创建时间
    private Timestamp createTime;

    // 更新时间
    private Timestamp updateTime;
}

2、封装工具类

这里把前面获取 IP 地址的方法也封装进来了,LogUtil 为封装的日志工具类

public class AuthUtil {

    private static InputStream database;

    private static DatabaseReader reader;

    static {
        // 读取数据库文件
        LogUtil.info("读取数据库文件");
        ClassPathResource classPathResource = new ClassPathResource("GeoLite2-City.mmdb");
        // 创建数据库
        try {
            database = classPathResource.getInputStream();
            reader = new DatabaseReader.Builder(database).build();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 获取 IP 地址
     *
     * @param request 请求
     * @return {@link String}
     * @author Fan
     * @since 2022/11/28 9:08
     */
    public static String getIpAddress(HttpServletRequest request) {
        // 首先, 获取 X-Forwarded-For 中的 IP 地址,它在 HTTP 扩展协议中能表示真实的客户端 IP
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (CommonUtil.isNotBlank(ipAddress) && !"unknown".equalsIgnoreCase(ipAddress)) {
            // 多次反向代理后会有多个 ip 值,第一个 ip 才是真实 ip, 例: X-Forwarded-For: client, proxy1, proxy2,proxy…
            int index = ipAddress.indexOf(",");
            if (index != -1) {
                return ipAddress.substring(0, index);
            }

            return ipAddress;
        }

        // 如果 X-Forwarded-For 获取不到, 就去获取 X-Real-IP
        ipAddress = request.getHeader("X-Real-IP");
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 X-Real-IP 获取不到, 就去获取 Proxy-Client-IP
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 Proxy-Client-IP 获取不到, 就去获取 WL-Proxy-Client-IP
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 WL-Proxy-Client-IP 获取不到, 就去获取 HTTP_CLIENT_IP
            ipAddress = request.getHeader("HTTP_CLIENT_IP");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 如果 HTTP_CLIENT_IP 获取不到, 就去获取 HTTP_X_FORWARDED_FOR
            ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (CommonUtil.isBlank(ipAddress) || "unknown".equalsIgnoreCase(ipAddress)) {
            // 都获取不到, 最后才通过 request.getRemoteAddr() 获取IP
            ipAddress = request.getRemoteAddr();
        }

        return ipAddress;
    }

    /**
     * 通过 IP 地址获取地理信息
     *
     * @param ipAddress IP地址
     * @return {@link LoginGeoDO}
     * @author Fan
     * @since 2022/12/14 16:35
     */
    public static LoginGeoDO getGeoInformation(String ipAddress) {
        try {
            // 获取 IP 地址信息
            InetAddress inetAddress = InetAddress.getByName(ipAddress);
            // 获取查询信息
            CityResponse response = reader.city(inetAddress);
            LoginGeoDO loginGeoDO = new LoginGeoDO();

            // 国家信息
            Country country = response.getCountry();
            loginGeoDO.setCountryIsoCode(country.getIsoCode());
            loginGeoDO.setCountryName(country.getName());
            loginGeoDO.setCountryZhCnName(country.getNames().get("zh-CN"));

            // 省级信息
            Subdivision subdivision = response.getMostSpecificSubdivision();
            loginGeoDO.setSubdivisionIsoCode(subdivision.getIsoCode());
            loginGeoDO.setSubdivisionName(subdivision.getName());
            loginGeoDO.setSubdivisionZhCnName(subdivision.getNames().get("zh-CN"));

            // 城市信息
            City city = response.getCity();
            loginGeoDO.setCityName(city.getName());
            loginGeoDO.setCityZhCnName(city.getNames().get("zh-CN"));

            // 邮政编码(国内的可能获取不到)
            Postal postal = response.getPostal();
            loginGeoDO.setPostal(postal.getCode());

            // 经纬度
            Location location = response.getLocation();
            loginGeoDO.setLatitude(location.getLatitude());
            loginGeoDO.setLongitude(location.getLongitude());

            return loginGeoDO;
        } catch (IOException | GeoIp2Exception exception) {
            LogUtil.error(exception.getMessage());
            return null;
        }
    }
}

3. 获取系统、浏览器信息

该类信息一般通过 UA(User Agent)标识来获取。 User Agent 中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等

先获取请求头中的 User-Agent

String ua = request.getHeader("User-Agent");

引入 UserAgentUtils 依赖

<!-- UserAgentUtils -->
<dependency>
    <groupId>eu.bitwalker</groupId>
    <artifactId>UserAgentUtils</artifactId>
    <version>1.21</version>
</dependency>

使用提供的 UserAgent 类来解析 ua 字符串文章来源地址https://www.toymoban.com/news/detail-790387.html

UserAgent userAgent = UserAgent.parseUserAgentString(ua);

// 操作系统
userAgent.getOperatingSystem().getName()
// 浏览器
userAgent.getBrowser().getName()

到了这里,关于通过 Request 请求获取真实 IP 地址以及对应省份城市的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# 通过 HttpWebRequest发送数据以及服务器通过Request请求获取数据

    C#中HttpWebRequest的用法详解 可参考: C#中HttpWebRequest的用法详解 C# HttpWebRequest详解 C# 服务器通过Request获取参数 可参考: C# WebService 接口 通过Request请求获取json参数 1、后台程序发送HTTP请求的Class,服务器端也要添加该类 2、服务端返回HTTP请求的数据class,客户端也要有 1、后台

    2024年02月06日
    浏览(59)
  • nginx代理后,nodejs如何获取用户真实ip地址(包括websocket获取用户真实IP地址)

    因为nginx代理的原因,我们在请求头中获取到的用户ip只是nginx代理的ip,并非用户真实ip,原因是经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,可以通过$remote_addr变量拿到的将是反向代理服务器的ip地址。 第一步,修改

    2024年02月13日
    浏览(75)
  • 【vue】前端获取用户真实IP地址 (外网IP地址)

    1. 打开index.html !-- 引入JS -- script src=\\\"http://pv.sohu.com/cityjson?ie=utf-8\\\"/script  2. 获取IP  let IP = returnCitySN[\\\"cip\\\"]; localStorage.setItem(\\\'ip\\\',IP);  完整代码:

    2024年02月16日
    浏览(58)
  • Django 获取真实ip地址

    2024年02月12日
    浏览(47)
  • docker 容器获取真实ip地址

    1、调用处 2、Iputils **特别注意:**如果使用到了nginx代理的话,需要在nginx.cofig内加上下面配置 效果: 加油,奥利给

    2024年02月16日
    浏览(43)
  • JavaWeb 获取客户端的真实IP地址

    通常我们在JavaWeb中获取客户端IP地址只需要使用 request.getRemoteAddr(); 方法即可 如果前端使用了Nginx等反向代理的话,我们使用 request.getRemoteAddr(); 方法获取到的IP地址就是 127.0.0.1 因为经过代理以后,在客户端和服务器之间增加了中间层,因此服务器无法直接拿到客户端的 IP 但

    2024年02月15日
    浏览(51)
  • Kubernetes Pod 获取真实 IP 地址

    1.1 链路介绍 7 层转发链路 : Client -- Nginx -- K8s Nginx Ingress 4 层转发链路: Client -- 公有云 SLB(或 F5、LVS、Haproxy 等)-- K8s Nginx Ingress 实际业务可能会串联更多层级的转发。例如 WAF、CDN、API Gateway 一般都是 7 层转发,LB、LVS 一般是 4 层 TCP 转发。 1.2 准备 Whoami 探针 whomai 是一个

    2024年02月16日
    浏览(39)
  • 获取客户端真实 IP 地址的最佳实践

    1. 业务上云带来性能收益 公司从去年全面推动业务上云,而以往 IDC 架构部署上,接入层采用典型的 4 层 LVS 多机房容灾架构,在业务高峰时期,扩容困难(受限于物理机资源和 LVS 内网网段的网络规划),且抵挡不住 HTTPS 卸载引发的高 CPU 占用。 而经过压力测试发现,使用

    2024年02月05日
    浏览(58)
  • nginx获取不到真实ip地址,注意这个细节

    1 一定要把proxy_pass语句放在最后面 location / {         proxy_set_header Host $host;         proxy_set_header X-Real-IP $remote_addr;         proxy_set_header REMOTE-HOST $remote_addr;         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         client_max_body_size 1024m;         # 一

    2024年02月13日
    浏览(45)
  • Nginx代理后获取客户端真实IP地址

    在项目实际应用中,我们可能会需要获取到用户也就是客户端的真实IP地址,比如记录系统操作日志等情况。 通常情况下我们可以使用以下方式来获取IP地址 但是当我们使用Nginx反向代理项目地址后,使用以上方法只能获取到Nginx服务器的IP地址,并不是客户端的IP地址。 解决

    2023年04月11日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包