通过ip获取用户位置信息以及地区时间

news/2024/7/8 2:21:56 标签: tcp/ip, 网络, 网络协议

项目需要获取用户得位置信息以及地区时间,因为第一次搞,以防还有下次,特此记录

1.首先就是显得拿到用户得ip地址

先上代码:

    public  boolean checkIp(String ip) {
        return null == ip || ip.isEmpty() || "unknown".equalsIgnoreCase(ip);
    }

    public String getIp(HttpServletRequest request){
        // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
        String headerName = "x-forwarded-for";
        String ip = request.getHeader(headerName);
        if (null != ip && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值,第一个IP才是真实IP,它们按照英文逗号','分割
            if (ip.contains(",")) {
                ip = ip.split(",")[0];
            }
        }
        if (checkIp(ip)) {
            headerName = "Proxy-Client-IP";
            ip = request.getHeader(headerName);
        }
        if (checkIp(ip)) {
            headerName = "WL-Proxy-Client-IP";
            ip = request.getHeader(headerName);
        }
        if (checkIp(ip)) {
            headerName = "HTTP_CLIENT_IP";
            ip = request.getHeader(headerName);
        }
        if (checkIp(ip)) {
            headerName = "HTTP_X_FORWARDED_FOR";
            ip = request.getHeader(headerName);
        }
        if (checkIp(ip)) {
            headerName = "X-Real-IP";
            ip = request.getHeader(headerName);
        }
        if (checkIp(ip)) {
            headerName = "remote addr";
            ip = request.getRemoteAddr();
            // 127.0.0.1 ipv4, 0:0:0:0:0:0:0:1 ipv6
            if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    throw new SvcException(e.getMessage());
                }
                if(inet!=null){
                    ip = inet.getHostAddress();
                }
            }
        }
        return ip;
    }

原理:客户端想要跟服务端交互,必然经历三次握手,因此必然会告诉服务端自己得ip。再从服务端说起,如果服务器直接把IP暴漏出去,那么request.getRemoteAddr()就能拿到客户端ip。

但目前流行的架构中,基本上服务器都不会直接把自己的ip暴漏出去,一般前面还有一层或多层反向代理,常见的nginx居多。
加了代理后,相当于服务器和客户端中间还有一层,这时候request.getRemoteAddr()拿到的就是代理服务器的ip了,并不是客户端的ip。所以这种情况下,一般会在转发头上加X-Forwarded-For等信息,用来跟踪原始客户端的ip。

这时候,才会用上面的这些代码。解释下这些加上的信息
 

X-Forwarded-For:这是一个 Squid 开发的字段,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。格式为X-Forwarded-For:client1,proxy1,proxy2,一般情况下,第一个ip为客户端真实ip,后面的为经过的代理服务器ip。

Proxy-Client-IP/WL- Proxy-Client-IP:这个一般是经过apache http服务器的请求才会有,用apache http做代理时一般会加上Proxy-Client-IP请求头, 而WL-Proxy-Client-IP是他的weblogic插件加上的头。 这种情况也是直接能拿到。

HTTP_CLIENT_IP:有些代理服务器也会加上此请求头。

X-Real-IP:nginx一般用这个。

说到底就是一个一个测试。

Nginx 的作用与问题

Nginx 作为一个反向代理,主要是接收来自客户端的请求,然后将请求转发给后端的服务器。在这个过程中,Nginx 会修改 HTTP 请求的来源 IP 地址,替换为它自己的 IP 地址。这样的设计使得后端服务器只需要处理来自一个 IP 地址的请求,简化了很多复杂性。

然而,这种设计也带来了一个问题:后端服务器无法获取到真实的客户端 IP 地址。在很多应用中,获取真实的客户端 IP 地址是非常重要的,例如,进行地理定位、检测欺诈行为、限制访问速率等。

Nginx 配置的解决方法

要解决这个问题,我们可以在 Nginx 的配置中添加一些设置,以将客户端的真实 IP 地址添加到请求的 "X-Forwarded-For" 和 "X-Real-IP" 头中。在你的 Nginx 配置文件的相应 location 或 server 区块中添加以下行:

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

这些行的作用是将客户端的 IP 地址添加到每个请求的 "X-Real-IP" 和 "X-Forwarded-For" 头中。然后,你的应用就可以从这些头中读取到客户端的真实 IP 地址了。

实际操作步骤

一旦我们了解了原理,接下来就是实际操作步骤。在你的 Nginx 配置文件(通常为 /etc/nginx/nginx.conf 或 /etc/nginx/sites-available/default)中,找到你需要配置的 server 或 location 块,在其中添加上述的两行 proxy_set_header 配置:

location / {
    proxy_pass http://your_backend;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

经过前面步骤一般来说可以拿到我们得用户ip了

2.获取地理信息以及时区时间

我是用的ip2location来确立得位置信息以及时区信息。

先导入pom.xml

        <dependency>
            <groupId>com.maxmind.geoip2</groupId>
            <artifactId>geoip2</artifactId>
            <version>2.17.0</version>
        </dependency>

然后去官网下载一个GeoLite2-City.mmdb文件

最后直接上代码了

    public String info(HttpServletRequest request) throws IOException, GeoIp2Exception {
        String ip = getIp(request);
        String databasePath = "/tmp/GeoLite2-City.mmdb";
        File database = new File(databasePath);
        dbReader = new DatabaseReader.Builder(database).build();
        InetAddress ipAddress = InetAddress.getByName(ip);
        CityResponse response;
        try {
            response = dbReader.city(ipAddress);
        }catch (AddressNotFoundException e){
            throw new SvcException(CodeResponse.ADDRESS_ABNORMALITY);
        }
        String cityName = response.getCity().getName(); // 获取城市名称
        Country country = response.getCountry(); // 获取国家信息
        String countryName = country.getNames().get("zh-CN"); // 获取国家中文名称
        Location location = response.getLocation(); // 获取地理位置信息
        String timeZone = location.getTimeZone();   //时区
        TimeZone time = TimeZone.getTimeZone(timeZone);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        TimeZone.setDefault(time);
        Calendar calendar = Calendar.getInstance();
        Date date = calendar.getTime();
        String Time = format.format(date);
        return "国家:" + countryName + ";城市:" + cityName + ";时区:" + timeZone + ";时间:" + Time;
    }

参考:

java后端获取客户端(用户)真实ip,原理_用户请求后台时获取到用户地址-CSDN博客

Nginx反向代理及获取真实的客户端IP地址-腾讯云开发者社区-腾讯云 (tencent.com)

GeoLite2 City库的基本使用与下载, 通过ip查询地址_geolite2-city.mmdb 下载-CSDN博客

还有个博主自己写了个包,可以获取简单得地理位置信息:

根据IP获取地理位置Java(准确率99%)_java获取ip定位城市-CSDN博客


http://www.niftyadmin.cn/n/5536269.html

相关文章

g++和 gcc 编译入门教程

GNU GNU 编译器集合&#xff08;GNU Compiler Collection&#xff0c;简称 GCC&#xff09;是一个由自由软件基金会&#xff08;Free Software Foundation&#xff0c;简称 FSF&#xff09;开发的编译器系统&#xff0c;它是 GNU 项目的一部分。GCC 支持多种编程语言&#xff…

JAVA 对象存储OSS工具类(腾讯云)

对象存储OSS工具类 import com.qcloud.cos.COSClient; import com.qcloud.cos.ClientConfig; import com.qcloud.cos.auth.BasicCOSCredentials; import com.qcloud.cos.auth.COSCredentials; import com.qcloud.cos.model.ObjectMetadata; import com.qcloud.cos.model.PutObj…

Linux--V4L2应用程序开发(二)获取数据

一、采集数据流程 申请buffer用来放置摄像头数据 ioctl VIDIOC_REQBUFS&#xff1a;申请buffer&#xff0c;APP可以申请很多个buffer&#xff0c;但是驱动程序不一定能申请到 ioctl VIDIOC_QUERYBUF和mmap&#xff1a;查询buffer信息、映射 如果申请到了N个buffer&#xff0c…

边界无限陈佩文:红蓝对抗安全演练常态化的各方分析

虽然常态化演练尚未正式开始&#xff0c;但我们仍然希望对各方的表现进行一些分析和预测&#xff0c;以辅助我们对市场的判断和决策。同时&#xff0c;也希望通过这些初步的见解&#xff0c;抛砖引玉&#xff0c;引发更多有价值的讨论和观点。 “船停在码头是最安全的&#xf…

table = collections.defaultdict(list)申请的字典的类型是什么?

当你使用 collections.defaultdict(list) 来申请一个字典时&#xff0c;这个字典的类型是 defaultdict&#xff0c;但是其行为和表现方式在某些方面与普通的字典&#xff08;dict&#xff09;相似&#xff0c;主要区别在于它如何处理缺失的键。 defaultdict 是 Python 标准库 …

人工智能系列-numpy(一)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” Numpy是python语言的一个拓展程序库&#xff0c;支持大量的维度数组与矩阵计算&#xff0c;此外也针对数组运算提供大量的数学函数库 NumPy支持的数据类型比Python内置的类型要…

金融科技在反洗钱领域的创新应用及案例

随着金融科技的迅猛发展&#xff0c;其在反洗钱领域的应用也日益广泛和深入。这些创新应用不仅提高了反洗钱工作的效率和准确性&#xff0c;还为金融机构应对日益复杂的洗钱活动提供了有力支持。下面将详细介绍一些金融科技在反洗钱领域的创新应用案例。 一、AI大模型与知识图谱…

同步时钟:北斗/GPS卫星、电信基站、NTP以太网校时方式的区别

同步时钟是保证各设备时间统一的重要装置&#xff0c;广泛应用于电力、通信、金融、学校、医院、地铁等多个领域。目前&#xff0c;常用的同步时钟方式包括&#xff1a;北斗/GPS卫星、电信基站、NTP以太网等。 下面跟着小编来看一下这些校时方式及他们的区别吧。 1. 北斗/GP…