Nginx暴露出请求的真实IP的问题

 更新时间:2023年10月31日 16:51:32   作者:vnjohn  
在工作中,经常会用用户实际请求的IP地址,本文主要介绍了Nginx暴露出请求的真实IP的问题,具有一定的参考价值,感兴趣的可以了解一下

前言

在工作中,经常会用用户实际请求的 IP 地址,当需要记录到日志信息时或者在请求其他的第三方接口时需要用到实际的用户 IP 地址传入,在本节中会提供服务端在实际获取 IP 地址的源码以及通过 Nginx 代理后 IP 地址隐藏的问题

用途/场景

获取经纬度

无论是小程序还是 App 端,当用户未开启地理位置授权时,在前端页面是无法拿到当前用户所在的经纬度信息的,这时候还有另外一种途径来获取经纬度,那就是通过 IP 地址来解析用户真实请求时所在的经纬度

在一般情况下,都是由前端来拿到这块请求的 IP,可能由于某些 API 或版本的限制,导致前端在所获取的 IP 地址不准确,此时,不得不让后端的大佬 CASE 出手了

支付接口

微信 > 小程序支付文档中,终端IP:spbill_create_ip 参数是必填项,虽然在微信那一侧不会去校验这块的 IP 地址是否准确,但真实的 IP 地址有利用我们去排查线上问题,比如 IP 地址都是 127.0.0.1 这样的,你永远都分辨不出到底请求是从那一块服务进来的

白名单配置

当请求第三方接口 API 时,若我们所请求的 IP 地址未配置进白名单时,我们是无法从第三方获取到我们想要得到的信息的,这时候有了前置或后置日志打印我们请求时的 IP,能够更快的帮助我们解决问题

比较友善的第三方 API,在我们请求接口出现白名单的问题,会将我们的 IP 进行返回提示 “该 IP:Xxx,未配置白名单,请联系管理员!”,这时直接拿到返回的错误信息内容进行配置即可,无须任何的日志输入

但是有的第三方 API 就比较鸡肋,只是返回一段 "请求 IP 未配置白名单,请联系管理员!”,这时候如果不+日志打印,那中间去找部署服务的 IP 花费的时间就比这日志打印的时间多了个去

实现源码

请求工具类

/**
 * @author vnjohn
 * @since 2023/10/30
 */
public class IPv4Util {

    private static final String HEADER_FORWARDED_FOR = "x-forwarded-for";
    private static final String HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP";
    private static final String HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
    private static final String HEADER_HTTP_CLIENT_IP = "http_client_ip";
    private static final String HEADER_HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR";

    private static final String UNKNOWN = "unknown";
    private static final String CHAR_COLON = ":";
    private static final String CHAR_COMMA = ",";

    public static String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader(HEADER_FORWARDED_FOR);
        boolean ipIsEmpty = ip == null || ip.length() == 0;
        if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HEADER_PROXY_CLIENT_IP);
        }
        if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HEADER_WL_PROXY_CLIENT_IP);
        }
        if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HEADER_HTTP_CLIENT_IP);
        }
        if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HEADER_HTTP_X_FORWARDED_FOR);
        }
        // 如果是多级代理,那么取第一个ip为客户ip
        if (ip != null && ip.contains(CHAR_COMMA)) {
            ip = ip.substring(ip.lastIndexOf(CHAR_COMMA) + 1, ip.length()).trim();
        }
        //判断IP是否存在带有端口号的情况、应该要去掉端口号
        if (ip != null && ip.contains(CHAR_COLON)) {
            ip = ip.substring(0, ip.indexOf(CHAR_COLON));
        }
        return ip;
    }

    /**
     * 获取请求的ip
     */
    public static String getRequestIp() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取 RequestAttributes 中获取 HttpServletRequest 信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        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;
    }

    public static void main(String[] args) {
        System.out.println(getRequestIp());
    }
}

在其他地方,需要获取 IP 时,只需要按如下传入参数:

HttpServletRequest request

如下调用即可:

IPv4Util.getClientIp(request);

Nginx 代理配置

在 server 标签模块中指定的请求前缀配置一个 location 或直接在 server 标签内进行配置,如下:

location /app {
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_pass http://localhost:8084;
}

只有当设置了 proxy_set_header X-Real-IP 代理参数以后,获取服务请求的 IP 才是准确的

小结

注意:只有在 Nginx 代理配置以下内容以后,通过请求工具类才能获取到真实的 IP 地址!!!

总结

该篇博文主要介绍的是如何在服务端中获取用户请求的真实 IP 地址,通过几种用途/场景介绍其所在的必要性:获取经纬度、支付接口、白名单配置,当然,为了让你能够快速的运用起来,提供了请求工具类的源码以及告知你如何在 Nginx 进行代理配置,希望这篇短文能够帮助到您,解决您实际工作中的一些问题

到此这篇关于Nginx暴露出请求的真实IP的问题解决的文章就介绍到这了,更多相关Nginx暴露请求的真实IP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • nginx搭建文件服务器的详细过程

    nginx搭建文件服务器的详细过程

    这篇文章主要介绍了nginx搭建文件服务器,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • shell脚本定时统计Nginx下access.log的PV并发送给API保存到数据库

    shell脚本定时统计Nginx下access.log的PV并发送给API保存到数据库

    这篇文章主要介绍了shell脚本定时统计Nginx下access.log的PV并发送给API保存到数据库的实现方法 ,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-09-09
  • nginx实现一个域名配置多个laravel项目的方法示例

    nginx实现一个域名配置多个laravel项目的方法示例

    这篇文章主要介绍了nginx实现一个域名配置多个laravel项目的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • nginx 配置代理服务地址最后多加反斜杠和不加反斜杠的区别小结

    nginx 配置代理服务地址最后多加反斜杠和不加反斜杠的区别小结

    在使用Nginx配置代理服务时,地址最后是否添加反斜杠(/)会对代理的URL处理产生影响,下面就来具体介绍一下,感兴趣的可以了解一下
    2024-08-08
  • Nginx请求头丢失的问题解决

    Nginx请求头丢失的问题解决

    本文主要介绍了在使用Nginx进行请求转发时,遇到请求头参数丢失的问题,导致的原因可能是api_key_id和api_key_value这2个参数传递过程中丢失或则根本没传递,下面就来具体介绍一下
    2024-12-12
  • nginx中的日志切割详解

    nginx中的日志切割详解

    Nginx日志切割是定期将访问日志和错误日志分割成多个文件,以优化性能、便于管理和分析,常见的实现方法包括使用logrotate工具和编写自定义脚本,解决常见的问题如Nginx不再写入新日志和权限问题,需要确保正确的信号发送和权限设置
    2025-11-11
  • nginx proxy_redirect的作用及说明

    nginx proxy_redirect的作用及说明

    这篇文章主要介绍了nginx proxy_redirect的作用及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 详解Nginx Location配置

    详解Nginx Location配置

    本篇文章给大家分享了Nginx Location配置的相关步骤以及具体方法,有需要的朋友参考学习下。
    2018-05-05
  • Nginx部署SSL证书的过程

    Nginx部署SSL证书的过程

    SSL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本,这篇文章主要介绍了Nginx部署SSL证书的相关知识,需要的朋友可以参考下
    2022-10-10
  • 一文详解Nginx中location的使用方法

    一文详解Nginx中location的使用方法

    本篇博客介绍了nginx的核心配置模块中的location部分的详解,包括location的语法规则(=  ^~  ~  ~*  不带符号  \)的功能、用法以及详细的示例,通过本篇博客可以加深对location的使用的理解,需要的朋友可以参考下
    2026-04-04

最新评论