刘弘扬fine 2024-11-08 18:50 采纳率: 57.1%
浏览 27
已结题

nginx反向代理获取ip,java获取真实ip

nginx反向代理获取ip,java获取真实ip。需求是,前端vue跟java项目,部署到阿里云服务器后,vue运行在nginx中,需要通过java获取nginx代理后,用户客户端的ip,我本机的ip是

img


java代码是,


```java
 /**
     */
    @PostMapping("/sendTask")
    public String sendTask(@RequestBody TaskRequest request, HttpServletRequest servletRequest) {
        try {

            // 测试内容
           /* InetAddress localHost = InetAddress.getLocalHost();
            String localIpAddress = localHost.getHostAddress();
            System.out.println("本地 IP 地址: " + localIpAddress);*/

            String localIpAddress = getClientIp(servletRequest);
            log.info("客户端 IP 地址3: " + localIpAddress);
            return "Task sent successfully";
        } catch (Exception e) {
            e.printStackTrace();
            return "Error sending task";
        }
    }


    public String getClientIp(HttpServletRequest request) {
        // 打印所有可能来源的 IP 信息
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        String xRealIp = request.getHeader("X-Real-IP");
        String remoteAddr = request.getRemoteAddr();

        System.out.println("X-Forwarded-For: " + xForwardedFor);
        System.out.println("X-Real-IP: " + xRealIp);
        System.out.println("RemoteAddr: " + remoteAddr);

        // 检查 X-Forwarded-For 头
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            // 若有多个 IP(多个代理),取第一个
            String[] forwardedIps = xForwardedFor.split(",");
            String clientIpFromXForwardedFor = forwardedIps[0].trim();
            System.out.println("使用 X-Forwarded-For 提取到的客户端 IP: " + clientIpFromXForwardedFor);
            return clientIpFromXForwardedFor;
        }

        // 检查 X-Real-IP 头
        if (xRealIp != null && !xRealIp.isEmpty()) {
            System.out.println("使用 X-Real-IP 提取到的客户端 IP: " + xRealIp);
            return xRealIp;
        }

        // 最后使用 request.getRemoteAddr()
        System.out.println("使用 RemoteAddr 提取到的客户端 IP: " + remoteAddr);
        return remoteAddr;
    }

但是打印出来的ip地址是错的,图片如下,

img

nginx的配置是

```bash
#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format debug '$remote_addr - $remote_user [$time_local] "$request" '
                 '$status $body_bytes_sent "$http_referer" '
                 '"$http_user_agent" "$http_x_forwarded_for" "$http_x_real_ip"';
    access_log /var/log/nginx/access.log debug;

    client_max_body_size 10m;

    sendfile        on;
    keepalive_timeout  65;

    # 后台代理配置
    server {
        listen      9999;
        location / {
            proxy_pass  http://127.0.0.1:18881; # 转发规则
            proxy_set_header Host $host; # 保持主机头信息一致
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    # 前端接口映射
    server {
        listen  80;
        
        # 主页面配置
        location / {
            root dist;
            try_files $uri $uri/ /index.html;
            index index.html index.htm;
        }

        # 后端接口配置
        location /prod-api/ {
            proxy_pass  http://127.0.0.1:9999/; # 转发规则
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}


现在大概问题我知道在哪里,是在nginx配置里面,有哪位兄台帮忙下,如何把nginx.conf配置一下,让java获取到用户端的ip

  • 写回答

33条回答 默认 最新

  • 问答-莫得感情 2024-11-08 18:52
    关注

    ️题主您好️,目前由我为您解答👇🏼
    🧡参考谷歌智能助手,由吾为汝整理提供🧡

    你的问题在于 Nginx 的配置导致 Java 获取到的 IP 地址是 Nginx 代理服务器的地址(127.0.0.1),而不是用户的真实 IP。 这是因为你使用了两个 server 块,并且在转发过程中 X-Forwarded-For 头信息被覆盖了。

    以下是修改后的 Nginx 配置,以及解释:

    #user  nobody;
    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
        log_format debug '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for" "$http_x_real_ip"';
        access_log /var/log/nginx/access.log debug;
        client_max_body_size 10m;
        sendfile        on;
        keepalive_timeout  65;
    
        # 只需要一个 server 块
        server {
            listen 80;
    
            # 主页面配置
            location / {
                root dist;
                try_files $uri $uri/ /index.html;
                index index.html index.htm;
            }
    
            # 后端接口配置
            location /prod-api/ {
                proxy_pass http://127.0.0.1:18881/; # 直接转发到 Java 应用
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;      # 真实客户端IP
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 代理服务器链
            }
        }
    }
    

    关键修改和解释:

    1. 移除 9999 端口的 server 块: 你原来的配置中,请求经过了两次 Nginx 代理。第一次从 80 端口到 9999 端口,第二次从 9999 端口到 Java 应用。每次代理都会设置 X-Forwarded-For,导致 Java 获取到的是最后一个代理服务器(9999 端口对应的 Nginx)的地址。 直接将 80 端口的 /prod-api/ location 转发到 Java 应用端口 (18881) 即可,避免多次代理。

    2. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;: 这个配置很重要。$proxy_add_x_forwarded_for 会在已有的 X-Forwarded-For 头信息后追加当前 Nginx 的 IP 地址。如果客户端请求头中本来就带有 X-Forwarded-For,则追加在其后,形成一个IP地址链,方便追踪。如果客户端请求中没有 X-Forwarded-For 头,则 $proxy_add_x_forwarded_for 的值为客户端的真实 IP 地址。

    Java 代码优化建议:

    你的 Java 代码逻辑基本正确,但可以略微优化,更健壮地获取客户端真实IP:

    public String getClientIp(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
    
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            String[] ips = xForwardedFor.split(",");
            // 获取第一个非 unknown 的 IP 地址
            for (String ip : ips) {
                ip = ip.trim();
                if (!"unknown".equalsIgnoreCase(ip)) {
                    return ip;
                }
            }
        }
    
        // 如果 X-Forwarded-For 为空或都为 unknown,则 fallback 到其他头
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
    
        return request.getRemoteAddr(); // 最后 fallback 到 RemoteAddr
    }
    

    通过以上修改,你的 Java 应用应该就能获取到用户的真实 IP 地址了。

    总结:

    问题核心在于避免多次代理和正确使用 $proxy_add_x_forwarded_for 变量。 简化 Nginx 配置,只用一个 server 块,并确保正确设置 X-Forwarded-For 头,就能让 Java 代码获取到客户端的真实 IP。 Java 代码部分也建议进行一些防御性编程,处理 unknown 等情况。

    希望这个解答能帮到你! 记得重启 Nginx 使配置生效。

    评论

报告相同问题?

问题事件

  • 系统已结题 11月16日
  • 修改了问题 11月8日
  • 创建了问题 11月8日

悬赏问题

  • ¥15 多尺度特征图提取和融合
  • ¥15 微信小程序:渲染收货地址时页面不显示
  • ¥20 win7 64位DirectShow提示初始化失败如何解决?
  • ¥20 小规模孤立词识别系统设计
  • ¥15 关于Java对接海康威视车牌识别一体机SDK是否需要固定外网的IP?
  • ¥15 Linux扩容时,格式化卡住了:vgdispaly查看卷组信息,没有输出
  • ¥18 关于#ubuntu#的问题:使用背景-工作职责内有七八台ubuntu系统的电脑,平时需要互相调取资料,想实现把这几台电脑用交换机组成一个局域网,来实现指定文件夹的互相调取和写入
  • ¥20 求一个简易射频信号综测仪
  • ¥15 esp8266 tally灯 接收端改为发射端
  • ¥30 Labview代码调用access 数据库,相同代码其中一个调用不出来是为什么