Netty服务如何使用Nginx代理转发请求并获得原始IP

news/2024/11/9 5:06:42/

Nginx配置

Nginx启用stream模块,示例如下:

stream {upstream netty{server remote:8080;}server {listen       	8080;proxy_pass      netty;proxy_protocol  on;}
}

示例,代理远端8080的netty服务。
注意,获得原始客户端的IP关键配置在于:proxy_protocol on;这一行配置。如果不配置,在netty服务端是无法获得原始客户端ip,但是配置上之后,netty需要调整代码。

Netty配置

代理http协议的时候,可以通过增加X-Forwarded-For请求头传递。
然而TCP采用另一种方式,每次在建立连接的时候发送一个非常小的报告头信息,提供这些数据,注意也只发送一次。

我们在用Netty的时候,是需要提供相应的编解码器的,因此对于这个代理头Netty内置的有相应的Decoder.
类路径:io.netty.handler.codec.haproxy.HAProxyMessageDecoder

配置示例:

        protected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();if (enableProxy) {pipeline.addLast("proxyDecoder", new HAProxyMessageDecoder());}pipeline.addLast("frameDecoder", new FrameDecoder());pipeline.addLast("frameEncoder", new FrameEncoder());pipeline.addLast("protocolEncoder", new ProtocolEncoder());pipeline.addLast("protocolDecoder", new ProtocolDecoder());pipeline.addLast("channelHandler", new ChannelHandler());}

关键就是:

pipeline.addLast("proxyDecoder", new HAProxyMessageDecoder());

这个配置。
放的位置和顺序如上面的示例即可。当我们第一次获得请求头的时候,需要拿到原始的IP等信息,保存下来:

    @Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if (msg instanceof HAProxyMessage) {HAProxyMessage proxyMessage = (HAProxyMessage) msg;// 原始IPproxyMessage.sourceAddress();// 原始端口proxyMessage.sourcePort();} else {// 业务处理}}

源码说明

可能有的同学奇怪HAProxyMessageDecoder这个解码器放在最上面,对于正常请求有影响没?
答案是没有影响。

正如前面说的,是每次建立连接的时候发送且只发送一次,我们可以看下,HAProxyMessageDecoder的decode逻辑:

    @Overrideprotected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {// determine the specification versionif (version == -1) {if ((version = findVersion(in)) == -1) {return;}}ByteBuf decoded;if (version == 1) {decoded = decodeLine(ctx, in);} else {decoded = decodeStruct(ctx, in);}if (decoded != null) {// 注意这里,如果decode成功,会设置finished为truefinished = true;try {if (version == 1) {out.add(HAProxyMessage.decodeHeader(decoded.toString(CharsetUtil.US_ASCII)));} else {out.add(HAProxyMessage.decodeHeader(decoded));}} catch (HAProxyProtocolException e) {fail(ctx, null, e);}}}

留意注释里强调的:finished变量,接着往下看:

    @Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {super.channelRead(ctx, msg);if (finished) {// 后面都移除了ctx.pipeline().remove(this);}}

解码成功后,后面就将它移除了,所以不用担心后面读取正常请求数据的时候会被这个decoder影响到。


http://www.ppmy.cn/news/85130.html

相关文章

【阿里云】文本转语音方言— 阿里云语音合成,文本转语音方言工具类

目录 一、导入SDK坐标 二、文本转语音方言 —步骤和工具类 1.登录阿里云账号&#xff0c;创建一个语音合成项目和创建用户并设置权限。 2.获取appKey、accessKeyId、accessKeySecret在相应位置进行填写。 3.相应位置填写自己需要保存的本地路径。意思就是说&#xff0c;自…

实验二:熟悉常用的HDFS操作

实验环境: (1)操作系统:Linux(建议 Ubuntu 16.04 或 Ubuntu 18.04)。 (2)Hadoop 版本:3.1.3。 (3)JDK 版本:1.8。 (4)Java IDE: Eclipse。 实验内容与完成情况: (1)编程实现以下功能,并利用Hadoop提供的Shell命令完成相同任务。 ①向HDFS中上传任意文本文件,如果指定的文…

Linux-文本编辑命令sed

一、文本编辑工具sed Linux之sed命令详解 - zakun - 博客园 (cnblogs.com) sed 是一个流编辑器&#xff0c;将文件或标准输入的内容作为编辑的对象&#xff0c;对其按照需求进行修改 pattern space 模式空间&#xff0c;是一个缓冲区&#xff0c;sed从输入流中一行一行取出内…

【连续介质力学】张量场

张量场 张量场表示张量 T ( x ⃗ , t ) T(\vec x, t) T(x ,t)在空间 x ⃗ \vec x x 和时间 t t t中如何变化&#xff0c;将张量场视为可微函数 如果一个张量场不依赖于时间&#xff0c;则此张量场称为定常场&#xff0c;例如 T T ( x ⃗ ) T T(\vec x) TT(x )&#xff1b;相…

Java如何配置环境变量

Java如何配置环境变量 0. 前言1. 下载Java2. 配置环境变量2.1新建 Java_Home2.2 编辑Path情况1情况2 3. 验证安装 0. 前言 本节记录如何配置Java环境变量&#xff0c;用自己重装过的系统实操 操作系统&#xff1a;Windows10 专业版 Java版本&#xff1a;jdk1.7.0_07 1. 下载…

【SA8295P 源码分析】03 - SA8295P QNX Host 上电开机流程分析

【SA8295P 源码分析】03 - SA8295P QNX Host上电开机流程分析 一、阶段1 固件开机自检 (SM BIST):APPS PBL加载XBL后触发 INT_RESET进行Warm Reset二、阶段2 固件开机自检 (SM BIST):加载TZ,初始Hypervisor,启动QNX Kernel,加载并启动各子系统系列文章汇总见:《【SA8295P…

Flink自定义函数之表值聚合函数(UDTAGG函数)

1.表值聚合函数概念 自定义表值聚合函数&#xff08;UDTAGG&#xff09;可以把一个表&#xff08;一行或者多行&#xff0c;每行有一列或者多列&#xff09;聚合成另一张表&#xff0c;结果中可以有多行多列。 理解&#xff1a;假设有一个饮料的表&#xff0c;这个表有 3 列&a…

百度API实现自动写诗

作者介绍 张琪&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;2022级研究生 研究方向&#xff1a;机器视觉与人工智能 电子邮件&#xff1a;3126743452qq.com 王泽宇&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;2022级研究生&#xff0…