1.1 从回车到响应:请求的完整旅程


文档摘要

1.1 从回车到响应:请求的完整旅程 本节摘要:本节是全册的纲——用一个 HTTP 请求从浏览器出发到拿到响应的完整时间线,介绍 Tomcat 管道上的每一站:Connector 负责接客与协议解析,Engine、Host、Context、Wrapper 四层容器负责指路,Valve 与 Filter 在途中检查,Servlet 在终点处理,响应沿原路返回。后续六章的每一章,都是这条时间线上某一段的放大图。 这一节在知识体系中的位置:它是第 1 章的骨架,也是第 3 章到第 6 章的总目录;先在这里把站名记熟,后文每次深入某一站时你都能立刻对上号。

1.1 从回车到响应:请求的完整旅程

本节摘要:本节是全册的纲——用一个 HTTP 请求从浏览器出发到拿到响应的完整时间线,介绍 Tomcat 管道上的每一站:Connector 负责接客与协议解析,Engine、Host、Context、Wrapper 四层容器负责指路,Valve 与 Filter 在途中检查,Servlet 在终点处理,响应沿原路返回。后续六章的每一章,都是这条时间线上某一段的放大图。

这一节在知识体系中的位置:它是第 1 章的骨架,也是第 3 章到第 6 章的总目录;先在这里把站名记熟,后文每次深入某一站时你都能立刻对上号。

先把整条时间线摊开

图 1-1:一次 GET 请求在 Tomcat 内的旅程时间线

图 1-1:一次 GET 请求在 Tomcat 内的旅程时间线

每一站只做一件事

看图之后逐站说清楚职责边界,这是理解 Tomcat 的关键——它把"接客、指路、检查、干活"分给了四组不同的组件,配置文件里的每个标签,都只属于其中一组。

进城的一段属于 Connector。请求到达服务器网卡后,操作系统完成 TCP 三次握手,连接器监听的端口(默认 8080)接到这条连接,把字节流按 HTTP 协议解析成 Tomcat 内部的请求对象。线程池在这里登场:连接器从池里取一个工作线程,把后续处理都交给它,自己回去等下一个连接。maxThreads、acceptCount、connectionTimeout 这些耳熟能详的参数,全部作用于这一段。

指路的一段属于容器。Engine 看请求头里的主机名,决定这个请求属于哪个虚拟主机;Host 看路径里的第一段,决定它属于哪个 Web 应用;Context 看剩余路径,按 Servlet 映射规则找到具体的 Wrapper;Wrapper 管理着那个 Servlet 实例。四层各查一次"户口",请求就从千千万万个 Servlet 里被精确递到该处理它的那个面前。

检查的一段嵌在管道上。Valve 挂在容器各级,像管道上的闸门,AccessLogValve 就是靠它在回程时写下访问日志;Realm 是身份档案库, BASIC 或 FORM 认证时请求会在这里被拦下核对;Listener 不拦请求,它在旁边监听容器和应用的生命周期事件;JNDI 则像资源调度台,把数据库连接池这类资源登记在容器里,供应用按名字取用。

干活的一段在终点。过滤器链先于 Servlet 执行,编码转换、登录校验、日志埋点都适合放在这里;链的末端是 Servlet 的 service 方法,它按请求方法分发到 doGet 或 doPost。JSP 本质上是"还没编译的 Servlet",首次访问时被 Jasper 编译,所以第一次总比后面慢——这不是玄学,是这条管道的固有行为。

💡 关键直觉:所谓"性能调优",一半以上是在给这条时间线上的某一站减负——线程池不够是进城段的事,路由慢是指路段的事,过滤器写得笨是终点段的事。先定位站,再谈优化。

用一次真实访问验证旅程

纸上谈兵不如亲手验证。下面是在本机装好 Tomcat 后的一次完整观察,两段会话分别对应"请求进入"与"日志落盘",你可以照着做一遍。

第一段:用 curl 模拟浏览器,观察响应头里暴露的管道信息。

# 向默认 8080 端口发起请求,只看响应头 curl -I http://localhost:8080/
HTTP/1.1 200 Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 21 Aug 2026 09:14:03 GMT

注意两点:默认安装的响应里没有 Server 头,这是 Tomcat 出于安全的默认克制;200 状态码说明请求走完了全程。若你装的是带示例应用的原版发行包,返回的正是根目录的欢迎页——一个静态资源,由 DefaultServlet 处理,它也是管道终点的住户之一。

第二段:打开访问日志,看请求在回程时留下的脚印。

# 进入日志目录,实时跟踪访问日志(Tomcat 9/10 路径一致) tail -f logs/localhost_access_log.2026-08-21.txt
0:0:0:0:0:0:0:1 - - [21/Aug/2026:17:14:03 +0800] "HEAD / HTTP/1.1" 200 - 0:0:0:0:0:0:0:1 - - [21/Aug/2026:17:15:11 +0800] "GET /docs HTTP/1.1" 302 - 0:0:0:0:0:0:0:1 - - [21/Aug/2026:17:15:11 +0800] "GET /docs/ HTTP/1.1" 404 -

这三行脚印分别对应:刚才的 HEAD 请求;一次对应用目录的重定向(302,发生在指路段——Context 判断路径后要求补斜杠);一次 404(终点段找不到资源)。同一条管道,不同状态码对应不同站点的裁决,这就是后面排障章节反复使用的"按站归因"思路。

常见问题:旅程里的两个疑惑

**为什么第一次访问特别慢,之后明显变快?**两种常见原因:JSP 首访要现场编译,编译产物缓存后同页再访就快了(6.2 会展开整条编译流水线);Servlet 没配启动加载,初始化成本落在重启后的第一个请求上(4.3 讲过 load-on-startup)。区分方法看慢的分布——只在改过页面后出现的是编译,重启后第一批请求才慢的是初始化。

**响应都返回了,连接为什么不断开?**这是长连接在起作用。HTTP/1.1 默认复用连接:一次请求结束后连接先挂起,客户端若紧接着发下一个请求,就省掉一次握手与慢启动。连接空闲超过保持活动的超时时间后由容器回收,这正是 3.1 里"超时与保活"岗位的职责。理解这一点对容量估算很重要——并发连接数不等于并发请求数,前者通常远大于后者。

本节要点回顾

  • 一段旅程,四组组件:Connector 接客、容器指路、管道组件检查、Filter 与 Servlet 干活,边界清晰不越权。
  • 四层容器是四次查户口:Engine 查主机名、Host 查上下文路径、Context 查 Servlet 映射、Wrapper 保管实例。
  • JSP 首访慢是固有行为:Jasper 要在第一次访问时把它编译成 Servlet,缓存之后才快。
  • 访问日志是回程留下的脚印:状态码能反推请求停在哪一站,200 走完全程、302 是指路段重定向、404 是终点段落空。
  • 参数有住址:看到任何 Tomcat 参数先问它作用于哪一站,这个问题会贯穿全册。

下一节把镜头拉远:这条管道在真实生产里很少单独露面,它的前面通常还站着一位 Nginx——两者的分工边界,就是 1.2 的主题。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U