
服务端日志里先出现 103 时,容易误以为这次请求已经拿到页面响应。其实 103 是一个信息性响应,后面还会有最终响应。把它们混作同一次响应,排查加载顺序时就会误判:提示到了,不代表文档已经返回。
103 到了,请求为什么没结束?
HTTP 一次请求可以先收到信息性响应,再收到最终响应。103 Early Hints 属于前者,常见用途是带上 Link 资源提示,让客户端有机会提前准备资源。它只提供提前处理的线索,最终状态码还未知。
客户端收到 103 后仍要继续读取同一连接上的后续响应。最终响应可能是 200,也可能是错误状态;在它到达之前,请求仍处于等待中。服务端如果只写出 103 就不再发送最终响应,客户端不会因为看到了提示而自动把请求当作完成。
验证范围放在这条边界:服务端先发 103,客户端能不能看到它,随后是否仍然拿到最终状态和正文。实验用 Node 的 HTTP 客户端,不用 fetch。前者有 information 事件,能直接观察中间响应;浏览器的资源调度另有一层,不在这次验证范围内。
Node 客户端把哪一段当作信息?
本机服务通过 writeEarlyHints() 写出一条带 Link 的 103,延迟 25 毫秒后再发送 200 和 page body。客户端在 information 事件里记录中间响应,最终响应仍由正常的响应回调收集。运行环境是 Node v26.8.1,服务绑定到回环地址,没有访问外部网络。
实际请求是 GET /page。客户端先记录到 103 和 Link: </app.css>; rel=preload; as=style,随后收到状态 200 和正文 page body。原始日志如下:
request: GET /page
client information: 103 link=</app.css>; rel=preload; as=style
client final: 200 page body
assertion: PASS (103 is informational; final response is 200)
顺序是重点。information 事件没有替代最终响应回调,也没有把请求结束掉。日志只能证明 Node HTTP 客户端实际接收到了信息性响应,并继续收到最终响应;它不证明浏览器一定按 Link 发起了预加载,也不证明任意代理都会原样转发 103。
Link 提示会让页面马上出现吗?
不会。103 携带的是服务端可提前提供的提示,客户端仍要决定是否采取动作。浏览器可能根据 Link 提前调度资源,但最终响应的状态和头部仍要等它到达。把 103 当作页面正文或成功状态,都超出了它的作用。
提示也不能代替正确的最终响应。比如 CSS URL 错了,预加载提示只会更早暴露一次失败;最终响应若返回错误,103 不会把它改成成功。应用应确保提示里的目标和正式文档使用的资源一致,并且不要把必须依赖最终认证结果才能确定的内容提前暴露。
实验脚本是 tools/verify-fullstack-early-hints-20261027.mjs,原始输出保存在同目录的 .log 文件。服务只模拟一次 103 后接 200 的路径。没有测浏览器预加载时机,没有经过反向代理,也没有比较不同客户端的行为。需要评估这些环节时,必须在相应浏览器或代理前另做实验,不能从这次日志外推。
如果客户端库能区分信息性响应,103 就适合用于观察服务端提示是否到达;应用业务仍应以最终响应为准。我选择保留 Node HTTP 客户端这条窄验证,而不把浏览器网络面板当成证据,因为后者无法单独说明提示是由哪个响应阶段触发的。只有确认目标客户端和中间代理都支持这条路径后,提前提示才值得进入生产配置。