docker:Java通过nginx获取客户端的真实ip地址

news2024/11/6 3:15:09

问题现象

  • 我们的平台使用Spring Cloud微服务架构,使用Spring Boot构建Java服务,使用google的jib插件打成docker镜像包
  • 我们使用docker虚拟化部署,使用docker-compose统一管理所有服务,包括Java服务和nginx等组件
  • 我们前后端分离,前端通过nginx访问我们的网关(Spring Cloud Gateway),再转发到对应的Java服务
  • 我们需要记录一些基础业务数据变动日志,于是在过滤器里拦截对应请求记录日志
  • 在记录操作的来源ip时,记录了一个172.18.0.x的地址,这个明显不是实际客户端来源的ip

排查解决

  • 我们使用getRemoteAddres(request)获取的ip地址,按理说是能获取到客户端的真实ip地址的
  • 地址不对,想着从request的header里直接获取,参考网上的方法,查看哪个header参数里有ip地址
    log.info("X-Real-IP={}", request.getHeader("X-Real-IP"));
    log.info("X-Original-Forwarded-For={}", request.getHeader("X-Original-Forwarded-For"));
    log.info("X-Forwarded-For={}", request.getHeader("X-Forwarded-For"));
    log.info("x-forwarded-for={}", request.getHeader("x-forwarded-for"));
    log.info("Proxy-Client-IP={}", request.getHeader("Proxy-Client-IP"));
    log.info("WL-Proxy-Client-IP={}", request.getHeader("WL-Proxy-Client-IP"));
    log.info("HTTP_CLIENT_IP={}", request.getHeader("HTTP_CLIENT_IP"));
    log.info("HTTP_X_FORWARDED_FOR={}", request.getHeader("HTTP_X_FORWARDED_FOR"));
  • 结果发现,只有X-Forwarded-For能获取到地址,还是那个错误的172.18.0.x的地址
    在这里插入图片描述

  • 地址不对,应该是哪里出了问题,可能是docker网络、nginx代理或者gateway网关

  • 进一步排查,这个地址之前看到过,172.1x.0.x,是docker网络生成的ip地址

  • 使用docker命令docker network ls,查看了docker网络后,发现我们确实用的是这个
    在这里插入图片描述

  • 继续查看各个docker服务的ip,确定下这个ip是哪个服务的,具体来说,是nginx的、gateway的,还是具体的这个Java应用的

  • 使用docker exec -it 服务名 /bin/bash进入docker容器内部,使用cat /etc/hosts查看网络配置

  • 对比发现这个ip是nginx服务的,说明获取客户端远程地址时,获取到了nginx的ip
    在这里插入图片描述

  • nginx是决定能获取到正确的客户端请求ip地址的,因为它的log日志输出里,是有来源ip的
    在这里插入图片描述

修改nginx配置

  • 查看了nginx的配置文件default.conf,发现里面没有其他配置,已有的X-Forwarded-For配置为proxy_set_header X-Forwarded-For $proxy_protocol_addr;,这里直接把nginx代理服务自己的地址赋给了X-Forwarded-For,所以我们获取到的是nginx的地址
  • 我们现在需要做的,主要是在主配置文件,添加一行proxy_set_header X-Real-IP $remote_addr;,将客户端的真实ip地址,赋给X-Real-IP
  • 执行命令docker restart nginx,重启nginx使其生效

Java代码

  • Java代码修改也很简单,对应nginx的配置,获取X-Real-IP即可
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
  • 成功获取,结束
    在这里插入图片描述

nginx配置proxy_set_header介绍

在Nginx配置中,proxy_set_header 指令是用于定义向代理服务器传递的请求头字段。该指令专门用于location块中,并且通常配合 proxy_pass 指令一起工作,proxy_pass 指令定义了代理服务器的协议和地址。

基本上,当Nginx作为反向代理服务器时,客户端的请求首先到达Nginx,然后Nginx将这些请求转发到后端的上游服务器。在转发请求时,Nginx可以设置或修改请求头。proxy_set_header 指令正是用来进行这样的设置或修改。

下面是几个proxy_set_header 常见用例:

  • 传递主机名 - 将客户端请求的原主机头信息传递到上游服务器。

    proxy_set_header Host $host;
    
  • 传递真实IP地址 - 将客户端的真实IP地址传递给后端应用,这在后端应用需要记录真实的客户端地址时非常有用。

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
  • 传递HTTPS相关信息 - 当Nginx用作SSL终结时,它可以告诉后端应用请求是通过HTTPS或HTTP进行的。

    proxy_set_header X-Forwarded-Proto $scheme;
    
  • 用户的Worker处理状态: 有时,应用程序可能需要知道客户端连接的具体状态。

    proxy_set_header Connection $connection_upgrade;
    

标准的 proxy_set_header 指令使用方法如下:

proxy_set_header Header-Name Header-Value;
  • Header-Name 是你希望设置的HTTP请求头名称。
  • Header-Value 是对应的值,它可能是一个固定的字符串,也可以是Nginx提供的变量,如 $remote_addr$http_user_agent$http_cookie 等。

注意,默认情况下,Nginx会使用某些标准请求头,如HostConnection等,如果你没有明确使用proxy_set_header设置它们,Nginx会传递它的默认值。

在调整Nginx作为反向代理服务器时,正确配置proxy_set_header指令能确保后端服务器可以接收到所需的所有重要信息,提供正确和安全的服务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1395462.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JVM】并发的可达性分析详细解释

​ 🍎个人博客:个人主页 🏆个人专栏:JVM ⛳️ 功不唐捐,玉汝于成 ​ 目录 前言 正文 可达性分析的基本原理: 根集合(Root Set): 对象引用关系: 标记…

el-tabs 切换之前进行拦截

tabs标签页在切换的时候进行提示,点击确定执行,点击取消不切换 element文档:before-leave切换标签之前的钩子,若返回 false 或者返回 Promise 且被 reject,则阻止切换。 这里有个坑就是直接return false 不生效&#…

网易云音乐 API

网易云音乐 API 网易云音乐 API灵感来自环境要求安装运行Vercel 部署操作方法 可以在Node.js调用支持 TypeScript使用文档功能特性更新日志单元测试SDK贡献者License 网易云音乐 API 网易云音乐 Node.js API service 灵感来自 disoul/electron-cloud-music darknessomi/musi…

Leetcode2182. 构造限制重复的字符串

Every day a Leetcode 题目来源:2182. 构造限制重复的字符串 解法1:贪心 双指针 我们先用一个长度为 26 的数组 cnt 统计字符串 s 中每个字符出现的次数,然后从大到小枚举字母表的第 i 个字母,每次取出最多 min⁡(cnt[i], re…

微信小程序(七)navigator点击效果

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.默认效果 2.无效果 3.激活效果 源码&#xff1a; index.wxml //如果 <navigator url"/pages/logs/logs">跳转到log页面&#xff08;默认&#xff09; </navigator><navigator url"/pa…

Spring WebSocket实现实时通信的详细教程

简介 WebSocket 是基于TCP/IP协议&#xff0c;独立于HTTP协议的通信协议。WebSocket 连接允许客户端和服务器之间的全双工通信&#xff0c;以便任何一方都可以通过已建立的连接将数据推送到另一方。 我们常用的HTTP是客户端通过「请求-响应」的方式与服务器建立通信的&#x…

Jmeter的文件参数化:CSV数据文件设置和_CSVRead函数

一、CSV数据文件设置 1、简介 CSV数据文件配置&#xff08;CSV Data Set Config&#xff09;可以将CSV文件中数据读入自定义变量中 Jmeter中CSV数据文件配置的界面如下图所示&#xff1a; 其中&#xff1a; &#xff08;1&#xff09;文件编码 文件的编码格式&#xff0c;与所…

Java网络编程——UDP通信原理

一、TCP和UDP概述 传输层通常以TCP和UDP协议来控制端点与端点的通信 TCPUDP协议名称传输控制协议用户数据包协议是否连接面向连接的协议。数据必须要建立连接无连接的协议&#xff0c;每个数据报中都给出完整的地址信息&#xff0c;因此不需要事先建立发送方和接受方的连接是…

200SMART作为智能控制器和智能设备使用

200SMART固件版本在V2.5以上的标准型CPU都支持PROFINET IO控制器和IO设备使用。 S7-200SMART作为智能设备仅支持1个IO控制器&#xff0c;可配置的输入输出存储区都为128个字节&#xff0c;地址范围分别为I(Q)1152.0到I(Q)1279.7;每个CPU支持最多8个PROFINET IO设备&#xff0c…

CentOS 6.10 安装图解

特特特别的说明 CentOS发行版已经不再适合应用于生产环境&#xff0c;客观条件不得不用的话&#xff0c;优选7.9版本&#xff0c;8.5版本次之&#xff0c;最次6.10版本&#xff08;比如说Oracle 11GR2就建议在6版本上部署&#xff09;&#xff01; 引导和开始安装 选择倒计时结…

【Python】如何快速知道当前python所用库的路径

【背景】 项目一多&#xff0c;python环境就开始互相影响。有时需要快速知道当前的环境用的库&#xff0c;也就是site-pachage是哪个路径下的。 【方法】 打开相应的Python.exe&#xff0c;进入python命令行&#xff0c;输入&#xff1a; import sys print(sys.path)结果类…

canal server初始化源码分析

CanalLauncher类是canal server端启动的入口类&#xff0c;跟随代码进行深入。 在开始之前&#xff0c;我们可以先了解下&#xff0c; canal 配置方式 ManagerCanalInstanceGenerator&#xff1a; 基于manager管理的配置方式&#xff0c;实时感知配置并进行server重启Spring…

Java-初识正则表达式 以及 练习

目录 什么是正则表达式&#xff1f; 1. 正则表达式---字符类&#xff08;一个大括号匹配一个字符&#xff09;&#xff1a; 2. 正则表达式---预字符类&#xff08;也是匹配一个字符&#xff09;&#xff1a; 正则表达式---数量词 &#xff08;可以匹配多个字符&#xff09;…

android studio 连接 夜神模拟器方法

android studio 连接 夜神模拟器方法 1、打开cmd 2、输入夜神模拟器的安装地址&#xff0c;至bin目录下 3、输入连接指令&#xff1a;nox_adb.exe connect 127.0.0.1:62001 4、连接成功会提示successfully 5、打开Android Studio&#xff0c;会就会出现连接的模拟器。

C#,入门教程(07)——软件项目的源文件与目录结构

上一篇&#xff1a; C#&#xff0c;入门教程(06)——解决方案资源管理器&#xff0c;代码文件与文件夹的管理工具https://blog.csdn.net/beijinghorn/article/details/124895033 创建新的 C# 项目后&#xff0c; Visual Studio 会自动创建一系列的目录与文件。 程序员后面的工…

Opencv小项目——手势数字刷TIKTOK

​ 写在前面&#xff1a; 很久没更新了&#xff0c;之前的实习的记录也算是烂尾了&#xff0c;但是好在自己的实习记录还是有的&#xff0c;最近也忙碌了很多&#xff0c;终于放假了&#xff0c;今天下午正好没事&#xff0c;闲来无事就随便做个小玩意吧。 思来想去&#xff…

python算法与数据结构(搜索算法和拓扑排序算法)---深度优先搜索

课程目标 了解树/图的深度遍历&#xff0c;宽度遍历基本原理&#xff1b;会使用python语言编写深度遍历&#xff0c;广度遍历代码&#xff1b;掌握拓扑排序算法 搜索算法的意义和作用 搜索引擎 提到搜索两个子&#xff0c;大家都应该会想到搜索引擎&#xff0c;搜索引擎的基…

android 和 opencv 开发环境搭建

本文详细说明给android项目添加opencv库的详细步骤&#xff0c;并通过实现图片灰度化来查看配置是否成功。 下载OPENCV ANDROID SDK 到官网下载 打开 https://opencv.org/releases/ 选择android&#xff0c;下载完成后解压出下面的文件&#xff1a; 安装android sdk 和 ndk …

Tide Quencher 7.2 CPG 500A ,TQ7.2 CPG 500A,可以提高荧光标记物的淬灭效果

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;荧光淬灭剂Tide Quencher 7.2 CPG 500A&#xff0c;Tide Quencher 7.2 CPG 500A &#xff0c;TQ7.2 CPG 500A 一、基本信息 产品简介&#xff1a;The fluorescence quencher Tide Quencher 7.2 CPG 500A can quench…

Android Dialog setCanceledOnTouchOutside失效,点击dialog外面不消失

前言&#xff1a;有一个需求需要点击dialog外面要消失&#xff0c;本来以为很简单结果设置了一直未生效 setCanceledOnTouchOutside(true); 问了半天chat-gpt4结果给的答案都不明显 查看代码发现设置了style&#xff0c;于是尝试去除这个style&#xff0c;结果点击setCancele…