关于本文
本文是通过利用生成式 AI 的自动化流程创建的。我们确认了 RFC 8297 和 Node.js 的 writeEarlyHints 规范,并构建了一个在 localhost 上区分信息响应与最终响应的实验。该实验未在目标环境中实际运行。
验证状态:📘 已查阅 RFC 及 Node.js 官方文档/未进行实机验证
HTTP 状态码并不只有 200 或 404。103 Early Hints是一种信息响应,它允许服务器在返回 HTML 等最终响应之前,向浏览器传递资源预加载的候选项。仅凭看到 103,并不能判断网站是否已正常完成响应。
我们将在 localhost 上观察这种区别。只要有 Node.js 18.11 或更高版本以及 curl,无需外部网站即可进行尝试。
HTTP 103 与 200 的作用
クライアント サーバー
GET / -------->
<-------- 103 Early Hints
Link: </style.css>; rel=preload
<-------- 200 OK
最終HTML
RFC 8297 将 103 定义为信息响应 (informational response)加载的“提示”是供客户端进行前期准备的素材。它并不能替代最终 200 或 500 的含义。
| 状态码 | 主要作用 | 是否用于判断成功 |
|---|---|---|
| 103 Early Hints | 提供 Link 等预先线索 | 不可单独使用 |
| 200 OK | 正常的最终响应 | 结合响应内容进行判断 |
| 404 Not Found | 未找到目标 | 作为最终结果进行确认 |
| 500 Internal Server Error | 服务器端异常 | 作为错误处理 |
尝试运行
early-hints-local.js创建一个名为该名称的文件。
const http = require("node:http");
const server = http.createServer((req, res) => {
if (req.url === "/style.css") {
res.writeHead(200, { "content-type": "text/css" });
res.end("body { color: navy; }");
return;
}
if (req.url !== "/") {
res.writeHead(404);
res.end("not found");
return;
}
// 最終応答の準備が終わる前にLinkヒントを送る
res.writeEarlyHints({
link: "</style.css>; rel=preload; as=style"
});
setTimeout(() => {
res.writeHead(200, {
"content-type": "text/html; charset=utf-8",
link: "</style.css>; rel=preload; as=style"
});
res.end("<!doctype html><h1>hello</h1>");
}, 700);
});
server.listen(30031, "127.0.0.1", () => {
console.log("http://127.0.0.1:30031/");
});
127.0.0.1由于仅在本地监听,因此不会对外公开。如果30031端口与其他进程冲突,请更改数字。
在终端A中启动服务器,在终端B中使用curl。
node early-hints-local.js
curl --http1.1 --include --no-progress-meter \ http://127.0.0.1:30031/
这是预期的响应顺序(并非实际设备输出)。
HTTP/1.1 103 Early Hints Link: </style.css>; rel=preload; as=style HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 ... <!doctype html><h1>hello</h1>
若要终止服务器,请按Ctrl+C。如果在启动Node.js时EADDRINUSE出现此提示,说明另一个程序正在占用该端口。请不要停止现有服务,而是更改示例一侧的端口。
Daily-Code-Samples:HTTP 103 本地实验已在其中放置了可执行版本和说明。
修改一处并进行观察
res.writeEarlyHints(...)注释掉该行,重新启动并执行相同的curl。这次预计103将会消失,只剩下最后的200。
// res.writeEarlyHints({
// link: "</style.css>; rel=preload; as=style"
// });
以此确认103和200是相互独立的。此外,在localhost上res.writeHead(500)更改为…就可以复现 103 响应虽早于返回、但随后依然报错的场景。
Link 标头的意义与局限
</style.css>; rel=preload; as=style的各个部分分别指示了预加载候选的 URL、关系(preload)以及作为样式表的处理方式。然而,浏览器并不一定会进行预加载。curl 中出现了标头,也并不代表 CSS 已经被下载。
资源是否真的被更快获取,需要通过浏览器开发者工具的“网络”(Network)面板或性能测试来进行验证。如果缓存生效,前提条件也会发生变化。
实际工作中的注意事项
代理/CDN 或旧版 HTTP/1.1 客户端可能无法按预期处理信息性响应。RFC 8297 中包含了关于信息性响应互操作性的安全注意事项。
此外,在 HTTP 监控处理中,切勿将最先出现的 103 视为“响应结束”。接收到 103、最终状态码为 200、预加载确实已执行这三点需要分别进行记录。
如果在真实网站上使用,请依次确认正确的 Link 目标、实际的最终响应、客户端兼容性以及对负载的影响。除非在引入前后进行实际测量,否则切勿断言速度有所改善。
