[netty5: HttpServerCodec HttpClientCodec]-源码分析

在阅读该篇文章之前,推荐先阅读以下内容:

  1. [netty5: ChannelHandler & ChannelHandlerAdapter]-源码解析
  2. [netty5: HttpObjectEncoder & HttpObjectDecoder]-源码解析

HttpServerCodec

HttpServerCodec 是一个 Netty 编解码器,结合 HttpRequestDecoderHttpResponseEncoder,用于处理 HTTP 请求和响应,并支持协议升级。

public final class HttpServerCodec extends CombinedChannelDuplexHandler<HttpRequestDecoder, HttpResponseEncoder> implements HttpServerUpgradeHandler.SourceCodec {private final Queue<HttpMethod> queue = new ArrayDeque<>();public HttpServerCodec() {// 4096 8192this(DEFAULT_MAX_INITIAL_LINE_LENGTH, DEFAULT_MAX_HEADER_SIZE);}public HttpServerCodec(int maxInitialLineLength, int maxHeaderSize) {init(new HttpServerRequestDecoder(maxInitialLineLength, maxHeaderSize),new HttpServerResponseEncoder());}@Overridepublic void upgradeFrom(ChannelHandlerContext ctx) {ctx.pipeline().remove(this);}
}

HttpServerRequestDecoder

HttpServerRequestDecoder 主要用于解码 HTTP 请求,并在解码时通过 queue 队列保存请求方法,以便在后续处理响应时进行配对。

private final class HttpServerRequestDecoder extends HttpRequestDecoder {private ChannelHandlerContext context;HttpServerRequestDecoder(int maxInitialLineLength, int maxHeaderSize) {super(maxInitialLineLength, maxHeaderSize);}HttpServerRequestDecoder(HttpDecoderConfig config) {super(config);}@Overrideprotected void decode(final ChannelHandlerContext ctx, Buffer buffer) throws Exception {super.decode(context, buffer);}@Overrideprotected void handlerAdded0(final ChannelHandlerContext ctx) {context = new DelegatingChannelHandlerContext(ctx) {@Overridepublic ChannelHandlerContext fireChannelRead(Object msg) {if (msg instanceof HttpRequest) {// 存放请求方法queue.add(((HttpRequest) msg).method());}super.fireChannelRead(msg);return this;}};}
}

HttpServerResponseEncoder

HttpServerResponseEncoder 负责处理 HTTP 响应编码,移除特定头部并根据请求方法决定响应内容是否为空。

private final class HttpServerResponseEncoder extends HttpResponseEncoder {private HttpMethod method;@Overrideprotected void sanitizeHeadersBeforeEncode(HttpResponse msg, boolean isAlwaysEmpty) {if (!isAlwaysEmpty && HttpMethod.CONNECT.equals(method) && msg.status().codeClass() == HttpStatusClass.SUCCESS) {msg.headers().remove(HttpHeaderNames.TRANSFER_ENCODING);return;}super.sanitizeHeadersBeforeEncode(msg, isAlwaysEmpty);}// 判断 HTTP 响应是否总是没有内容@Overrideprotected boolean isContentAlwaysEmpty(@SuppressWarnings("unused") HttpResponse msg) {// 响应完成,先查看当前响应的请求方法,如果是HEAD, 响应永远无内容,直接返回 truemethod = queue.poll();return HttpMethod.HEAD.equals(method) || super.isContentAlwaysEmpty(msg);}
}

HttpClientCodec

HttpClientCodec 是一个 Netty 编解码器,结合 HttpResponseDecoderHttpRequestEncoder,支持请求与响应的关联、连接升级处理,并提供配置选项来控制解析行为和响应缺失时的错误处理。

public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResponseDecoder, HttpRequestEncoder> implements HttpClientUpgradeHandler.SourceCodec {public static final boolean DEFAULT_FAIL_ON_MISSING_RESPONSE = false;public static final boolean DEFAULT_PARSE_HTTP_AFTER_CONNECT_REQUEST = false;// 用于控制在关闭通道时,请求数量 != 响应数量时,是否抛出异常。// 触发在 channelInactive, 如果为true, requestResponseCounter < 0 则抛出异常,否则忽略private final boolean failOnMissingResponse;// 用于跟踪 请求与响应对的数量 的计数器,具体来说,它用于 跟踪缺失的响应 数量。private final AtomicLong requestResponseCounter = new AtomicLong();// 用于指示是否在处理 CONNECT 请求后继续解析 HTTP 内容。// 如果为 true,则会在 CONNECT 请求后继续解析 HTTP 数据;// 如果为 false,则直接跳过解析private final boolean parseHttpAfterConnectRequest;// 用于指示解码是否停止,如果为true,则解码过程会被跳过,数据将直接传递下去。private boolean done;private final Queue<HttpMethod> queue = new ArrayDeque<>();public HttpClientCodec() {this(new HttpDecoderConfig());}public HttpClientCodec(HttpDecoderConfig config) {this(config, DEFAULT_FAIL_ON_MISSING_RESPONSE, DEFAULT_PARSE_HTTP_AFTER_CONNECT_REQUEST);}public HttpClientCodec(HttpDecoderConfig config, boolean failOnMissingResponse, boolean parseHttpAfterConnectRequest) {init(new Decoder(config), new Encoder());this.parseHttpAfterConnectRequest = parseHttpAfterConnectRequest;this.failOnMissingResponse = failOnMissingResponse;}@Overridepublic void prepareUpgradeFrom(ChannelHandlerContext ctx) {((Encoder) outboundHandler()).upgraded = true;}@Overridepublic void upgradeFrom(ChannelHandlerContext ctx) {final ChannelPipeline p = ctx.pipeline();p.remove(this);}public void setSingleDecode(boolean singleDecode) {inboundHandler().setSingleDecode(singleDecode);}public boolean isSingleDecode() {return inboundHandler().isSingleDecode();}
}

Encoder

Encoder 是 HttpRequestEncoder 的子类,用于编码 HTTP 请求。当协议已升级时,直接将消息添加到输出队列;否则,将 HTTP 请求的方法加入队列,并继续进行编码。如果启用了 failOnMissingResponse 且响应尚未完成,则会在处理完 LastHttpContent 后增加请求响应计数。

private final class Encoder extends HttpRequestEncoder {boolean upgraded;@Overrideprotected void encodeAndClose(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {// 当连接已经升级(比如从 HTTP 升级到 WebSocket 或其他协议),此时不需要再进行 HTTP 编码,直接将消息传递下去if (upgraded) {out.add(msg);return;}if (msg instanceof HttpRequest) {queue.offer(((HttpRequest) msg).method());}super.encodeAndClose(ctx, msg, out);// failOnMissingResponse 在缺少响应是报错,并且done未完成,msg是最后一段内容,此时统计// 否则跳过执行if (failOnMissingResponse && !done) {if (msg instanceof LastHttpContent) {// 当响应到达时,requestResponseCounter 会减少计数,表示某个请求已经得到了响应requestResponseCounter.incrementAndGet();}}}
}

Decoder

Decoder 是 HttpResponseDecoder 的子类,用于解码 HTTP 响应,并在协议升级时管理请求响应的匹配;在响应解码时处理特定状态码(如 HEAD 请求和 CONNECT 请求的响应),并通过队列同步请求和响应。此外,Decoder 支持在连接关闭时检查未匹配的响应并抛出异常。

private final class Decoder extends HttpResponseDecoder {private ChannelHandlerContext context;Decoder(HttpDecoderConfig config) {super(config);}@Overrideprotected void handlerAdded0(ChannelHandlerContext ctx) {// ctx = ByteToMessageDecoder.ByteToMessageDecoderContextif (failOnMissingResponse) {context = new DelegatingChannelHandlerContext(ctx) {@Overridepublic ChannelHandlerContext fireChannelRead(Object msg) {decrement(msg);super.fireChannelRead(msg);return this;}};} else {context = ctx;}}@Overrideprotected void decode(ChannelHandlerContext ctx, Buffer buffer) throws Exception {if (done) {int readable = actualReadableBytes();if (readable == 0) {return;}ctx.fireChannelRead(buffer.readSplit(readable));} else {super.decode(context, buffer);}}private void decrement(Object msg) {if (msg == null) {return;}// 每当收到一个请求并且没有收到相应的响应时,requestResponseCounter 会增加一个计数值,表示有一个请求缺少响应if (msg instanceof LastHttpContent) {requestResponseCounter.decrementAndGet();}}// 判断消息是否包含内容,特别针对一些特殊的 HTTP 方法和状态码(如 HEAD 请求、CONNECT 请求的响应)@Overrideprotected boolean isContentAlwaysEmpty(HttpMessage msg) {final HttpResponseStatus status = ((HttpResponse) msg).status();final HttpStatusClass statusClass = status.codeClass();final int statusCode = status.code();if (statusClass == HttpStatusClass.INFORMATIONAL) {return super.isContentAlwaysEmpty(msg);}HttpMethod method = queue.poll();        if (method != null) {char firstChar = method.name().charAt(0);switch (firstChar) {case 'H':if (HttpMethod.HEAD.equals(method)) {return true;}break;case 'C':// 协议升级成功if (statusCode == 200) {if (HttpMethod.CONNECT.equals(method)) {// 一旦 CONNECT 请求成功建立连接后,不再进行 HTTP 响应解析,直接跳过// 通常适用于已经成功建立隧道后,不再需要处理 HTTP 相关内容的情况(例如,HTTPS 或 WebSocket)if (!parseHttpAfterConnectRequest) {done = true;queue.clear();}return true;}}break;default:break;}}return super.isContentAlwaysEmpty(msg);}// 如果在关闭连接时发现有未匹配的请求(即计数器值大于零),则可以触发异常,表明有请求缺少响应。@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {super.channelInactive(ctx);if (failOnMissingResponse) {long missingResponses = requestResponseCounter.get();if (missingResponses > 0) {ctx.fireChannelExceptionCaught(new PrematureChannelClosureException("channel gone inactive with " + missingResponses +" missing response(s)"));}}}
}

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

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

相关文章

华为OD机试 2025B卷 - 数组组成的最小数字(C++PythonJAVAJSC语言)

2025B卷目录点击查看: 华为OD机试2025B卷真题题库目录|机考题库 + 算法考点详解 2025B卷 100分题型 最新华为OD机试 真题目录:点击查看目录 华为OD面试真题精选:点击立即查看 2025华为od 机试2025B卷-华为机考OD2025年B卷 题目描述 给定一个整型数组,请从该数组中选…

Ubuntu下Tomcat的配置

进入Tomcat的conf目录下 1 备份配置文件 cp server.xml server.xml.2下载server.xml&#xff0c;用notepad文本编辑器打开 2 修改Tomcat的端口号 找到如下内容<Connector port"8080" protocol"HTTP/1.1"connectionTimeout"20000"redirectPort…

Docker部Ollama安装、本地大模型配置与One-API接入

Docker 安装 Ollama Ollama 支持 Docker 安装,极大简化了部署流程。以下是具体步骤: 创建ollama文件夹 创建 docker-compose.yaml 文件新建一个 docker-compose.yaml 文件,内容如下: 编辑文件 …

ABB焊接机器人智能节气仪

在现代焊接工业中&#xff0c;ABB焊接机器人凭借其高精度、高效率等优势被广泛应用。而在焊接过程中&#xff0c;节气是一个重要的考量因素&#xff0c;这就凸显出ABB焊接机器人智能节气仪的重要性。ABB焊接机器人节气是提高焊接生产效益的关键环节。传统的焊接过程中&#xff…

摄影后期:使用Photoshop进行暗角控制

方法一&#xff1a;ctrlshiftR调出镜头校正工具&#xff0c;调整晕影 方法二&#xff1a;

pyhton基础【24】面向对象进阶五

目录 十五.多继承的继承顺序 - mro 调用父类方式不同导致结果不同 单继承中的super 简单总结 面试题 十六.魔术方法 魔术方法概述 魔术方法概览 __getattribute__属性 __getattribute__注意事项 常用的魔术方法 __doc__ __module__和__class__ __init__ __del__…

如何保障MySQL客户端连接数据库安全更安全

公司员工或外协人员&#xff0c;直接使用业务账号或高权限账号连接MySQL服务器&#xff0c;如同让数据在连接时减少风险——账号密码易泄露、操作行为难追溯、安全风险陡增&#xff01;尤其是在客户端连接环节&#xff0c;如何确保每一个接入点都安全可控&#xff0c;每一次操作…

机器学习入门:线性回归详解及Scikit-learn API使用指南

一、线性回归概述线性回归是统计学和机器学习领域中最基础、最广泛应用的预测建模技术之一。自19世纪初由弗朗西斯高尔顿(Francis Galton)首次提出以来&#xff0c;线性回归已成为数据分析的核心工具&#xff0c;在经济学、社会科学、生物统计学、工程学等众多领域发挥着重要作…

高斯牛顿法求解三维变换矩阵的数学推导

目录一、问题定义二、李代数基础三、雅可比矩阵推导四、高斯牛顿迭代1. 整体雅可比矩阵2. 正规方程构建3. 参数更新4. 李代数更新五、理论优势分析一、问题定义 给定两组三维点云&#xff1a;源点云 P{pi∈R3}i1NP \{p_i \in \mathbb{R}^3\}_{i1}^NP{pi​∈R3}i1N​&#xff0…

JAVA 商城系统为什么受欢迎?ZKmall开源商城灵活定制 + 插件接入适配市场

在电商系统开发这块&#xff0c;技术选得好不好&#xff0c;直接关系到平台稳不稳定、能不能扩展、适配能力强不强。JAVA 语言因为 “跨平台性突出、安全性高、可扩展性好” 这些特点&#xff0c;成了企业级电商系统的首选技术。而 ZKmall 商城基于 JAVA 开发的商城系统&#x…

【数据结构之哈夫曼树与编码实现】

文章目录 前言一、哈夫曼树与哈夫曼编码简介1. 什么是哈夫曼树&#xff1f;2. 为什么需要哈夫曼编码&#xff1f; 二、哈夫曼编码原理三、哈夫曼树的构建步骤详解1. 统计字符频率2. 定义哈夫曼树节点3. 最小堆&#xff08;优先队列&#xff09;的构造4. 合并节点&#xff0c;构…

基于Hadoop的京东厨具商品数据分析及商品价格预测系统的设计与实现

文章目录有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍数据采集用户界面系统展示管理员界面每文一语有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 本项目围绕“京东厨具数据分析系统的设计与实…

深入解析TCP:可靠传输的核心机制与实现逻辑(三次握手、四次挥手、流量控制、滑动窗口、拥塞控制、慢启动、延时应答、面向字节流、粘包问题)

Linux系列 文章目录 Linux系列一、TCP连接的建立与断开1.1 TCP 三次握手1.2 TCP四次挥手1. TCP连接的本质是应用层间的通信通道2. 断开连接的核心是终止应用层通信3. 常见误解澄清 二、TCP协议的机制2.1 流量控制2.2 滑动窗口2.2.1 滑动窗口的工作原理2.2.2 基于滑动窗口快重传…

基于开源AI智能客服、AI智能名片与S2B2C商城小程序的微商服务质量提升路径研究

摘要&#xff1a;在科技飞速发展的背景下&#xff0c;产品技术含量与复杂度显著提升&#xff0c;客户正确使用产品并体验其价值愈发依赖代理的专业指导与服务。本文聚焦开源AI智能客服、AI智能名片与S2B2C商城小程序在微商服务中的应用&#xff0c;通过分析其技术原理与实践案例…

[netty5: HttpHeaders HttpHeadersFactory]-源码分析

HttpHeaders HttpHeaders 是用于存储和操作HTTP请求或响应头部字段的接口。 // DefaultHttpHeaders, HttpHeadersFactory.TrailingHttpHeaders public interface HttpHeaders extends Iterable<Entry<CharSequence, CharSequence>> {static HttpHeaders emptyHead…

基于Flink 1.20、StarRocks与TiCDC构建高效数据处理链路教程

在大数据处理领域&#xff0c;实现高效、实时的数据处理与分析至关重要。Flink作为强大的流批一体化计算框架&#xff0c;结合StarRocks这一高性能的实时分析型数据库&#xff0c;再搭配TiCDC&#xff08;TiDB Change Data Capture&#xff09;用于捕获数据变更&#xff0c;能够…

便捷的Office批量转PDF工具

软件介绍 本文介绍的软件是一款能实现Office批量转换的工具&#xff0c;名为五五Excel word批量转PDF。 软件小巧 这款五五Excel word批量转PDF软件大小不到2M。 操作步骤一 使用该软件时&#xff0c;只需把软件和需要转换的Word或Excel文件放在同一个文件夹里。 操作步骤…

tcp长连接与短连接

TCP连接本身是一个传输层协议&#xff0c;它既可以实现长连接&#xff0c;也可以实现短连接。这取决于应用层的使用方式。 短连接&#xff08;Short Connection&#xff09; 特点&#xff1a;每次请求都建立新的TCP连接&#xff0c;完成后立即关闭流程&#xff1a;建立连接 →…

llvm polly,亲自测试

1&#xff09;下载并安装 Polly - Getting Started git clone https://github.com/llvm/llvm-project.git 大概需要半个小时&#xff0c;有时候被墙掉就打不开 2&#xff09; mkdir build && cd build cmake -DLLVM_ENABLE_PROJECTSclang;polly ../llvm cmake --b…

Spring AI 项目实战(十四):Spring Boot + Vue3 +AI + DeepSeek 实现空气质量智能预测系统(附完整源码)

系列文章 序号文章名称1Spring AI 项目实战(一):Spring AI 核心模块入门2Spring AI 项目实战(二):Spring Boot + AI + DeepSeek 深度实战(附完整源码)3Spring AI 项目实战(三):Spring Boot + AI + DeepSeek 打造智能客服系统(附完整源码)4