news 2026/11/5 15:37:22

Netty HTTP 请求如何进入 MVC:从请求接收到响应写回

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Netty HTTP 请求如何进入 MVC:从请求接收到响应写回

读 Netty 与 MVC 的集成代码时,可以先抓住三个位置:请求从哪里进入,谁来调用处理器,处理结果在哪里写回连接。

本文使用 TODAY Infrastructure 的同步 HTTP 请求作为例子。我是项目维护者,也向 Spring Framework、MyBatis 和 Halo 贡献过代码,其中一些问题是在维护本项目时发现的。项目部分实现来自 Spring Framework / Spring
Boot
的移植与适配,也有自己的实现。下文只介绍这套框架的分发骨架,注解匹配、参数解析和返回值转换的全部细节没有展开。

最小控制器与调用链

示例中/index返回字符串Hello。以下仅为控制器相关代码,不是独立启动项目:

importinfra.web.annotation.GET;importinfra.web.annotation.RestController;@RestControllerclassDemoController{@GET("/index")publicStringindex(){return"Hello";}}

请求处理的主干如下:

HttpRequest → HttpTrafficHandler.channelRead → 创建请求上下文 → HttpRequestExecutor.execute → HttpContext.run → DispatcherHandler.handleRequest → 处理器查找、执行与返回值处理 → 同步请求完成,响应写回

过滤器、异常和异步请求还会走其他分支。先连起主干,再读各个策略实现更容易定位。

请求接入:HttpTrafficHandler

channelRead收到的是 Netty 已解码的HttpRequest。它创建请求上下文,存入 Channel 属性,然后把上下文任务交给执行器:

executor.execute(httpContext,httpContext);

执行器的类型是HttpRequestExecutor。上下文同时实现Runnable,因此在这里既是请求信息,也是待执行任务。

HttpRequest 与 HttpContent

不要把收到请求头理解为请求体完整到达。后续HttpContent会交给 Channel 上保存的上下文,由onDataReceived继续处理。

这意味着请求体读取要和网络数据到达衔接,不能只包装一下请求头就结束适配。

执行器与线程模型

委托执行不意味着必然使用线程池或虚拟线程,具体要看实现和配置。

上下文任务的run方法检查解码错误等情况;正常请求会进入dispatcherHandler.handleRequest(this),并在finally清理上下文持有者。

MVC 分发:查找、调用与返回值处理

DispatcherHandler组织请求处理流程,其中有三个主要职责:

工作对应策略
查找请求处理器HandlerMapping
执行处理器直接调用 HttpRequestHandler,或由 HandlerAdapter 执行
处理返回值ReturnValueHandler

lookupHandler委托HandlerMapping.getHandler(context)查找处理器。找到后,若它实现HttpRequestHandler,直接调用handleRequest;否则通过HandlerAdapter执行。

返回"Hello"后,分发器还要选择返回值处理策略。此时取得的是 Java 对象,不等于响应已经发送给浏览器。执行失败的异常也有相应处理路径。

响应写回:NettyHttpContext

MVC 面向统一的infra.web.HttpContext。Netty 包内还有同名实现infra.web.server.netty.HttpContext,它继承NettyHttpContext并承担上下文任务入口。

统一接口减少了上层对 Netty 具体对象的直接依赖,适配层仍负责请求体、响应提交、断连及资源清理。

普通同步请求完成后,Netty 实现负责写回响应。NettyHttpContext.flush写出响应头和正文或文件,请求完成时还要处理结束标记及连接是否保持开启。

因此读源码时,可以把调用控制器、处理返回值、写回连接分开看,再沿请求完成路径把它们连起来。

运行示例

先根据仓库快速开始准备 JDK 与 Gradle 运行环境:

gitclone https://github.com/TAKETODAY/today-infrastructure.gitcdtoday-infrastructure/infra-samples ./gradlew infraRun

另开终端检查:

curl-ihttp://localhost:8080/index

预期状态 HTTP 200,正文Hello。如需调整端口:

./gradlew infraRun--args='--server.port=8081'curl-ihttp://localhost:8081/index

上面两条分别在服务终端和另一个请求终端执行,服务不会自然退出。

实测环境与范围

日期示例源码提交构建与运行方式结果
2026-10-1188f5240e85859d64eb3c9543a528afb41b53519fmacOS ARM64,JDK 25.0.1 / Gradle 9.8.0,隔离缓存与 Maven Local,执行 infraRun默认端口及 8081 返回 HTTP 200 / Hello
2026-10-13a880d8b5ba6bd73e65333fd73ec0679bd9b130dfmacOS ARM64,JDK 25.0.3 / Gradle 9.8.0 构建发行包,JDK 17.0.16 运行同一产物/index 返回 HTTP 200 / Hello

JDK 17 的结果只覆盖默认示例路径,没有用它执行 Gradle,也没有验证所有可选功能。示例解析的是 Maven 仓库中的5.0-Draft.8-SNAPSHOT,快照可能变化。

本文源码分析固定在7045f9c1fd1b4fdda909674807fa6fd433b2bed5;它与实测示例提交不同。克隆命令取得当前默认分支,运行时应结合当前快速开始说明,历史记录不等于当前提交的全功能验证。

源码位置

  • 示例控制器
  • HttpTrafficHandler.channelRead
  • HttpContext.run
  • DispatcherHandler 执行与完成
  • 返回值与异常处理
  • NettyHttpContext.flush

同作者博客文章:https://taketoday.cn/articles/today-infrastructure-netty-to-mvc

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 13:28:19

中国30米高精度DEM优化方案:哥白尼GLO-30数据处理与精度验证

做地形分析这些年,DEM选型一直是个容易让人纠结的问题。全球公开DEM里,ASTER、SRTM、ALOS、哥白尼都被不少人推荐过,可真落到中国区域的高精度地形应用上,我这两年固定用的还是哥白尼全球30米DEM(Copernicus DEM GLO-3…

作者头像 李华
网站建设 2026/10/23 4:14:31

Matlab车牌识别课程设计:蓝底白字全链路图像处理与工程化实现

简介:本资源是一份面向高校电子信息、自动化及计算机类专业学生的Matlab课程设计报告,聚焦车牌识别系统全流程实现,解决图像处理与模式识别综合实践问题。报告完整覆盖车辆检测、车牌定位(基于大范围搜索与候选区评判)…

作者头像 李华
网站建设 2026/10/24 4:50:38

2.1.2-2、V8R3迁移到V8R6-迁移介绍

一、迁移工具介绍 1、数据迁移工具 ​ 金仓支持应用系统离线迁移、在线迁移。 离线迁移(业务停机)一般使用 KDTS 完成全量迁移(所有对象定义和数据的迁移);在线迁移(业务不停机)使用 KFS&#x…

作者头像 李华
网站建设 2026/10/30 14:50:11

rad库鸿蒙化适配实战:从渲染机制到响应式治理

前阵子给一套跨端业务组件做鸿蒙化改造,页面级的功能都迁得差不多了,唯独卡在 rad 这个三方库里。它在 Android 和 iOS 上渲染 HTML 片段一直很稳,富文本、图文混排、Web 风格样式都能处理,但一放到鸿蒙环境就白屏、错乱、点击没反…

作者头像 李华
网站建设 2026/10/26 2:37:17

PostgreSQL元组管理核心:MVCC版本链、HOT更新与VACUUM防膨胀

先讲一个我实际运维里发生过的场景。某个系统上线后,业务表每天会被一个计划任务频繁UPDATE大量行,起初一切正常,跑了不到一个月,磁盘占用比预估多了快两倍,查询也开始明显变慢。当时的排查思路从慢SQL和索引效率一路查…

作者头像 李华