[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fDjdtszP5PxCJZAtEPuOrXYf462_IiJcZF6mEU0BzWVQ":3},{"item":4,"related":44},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":35,"sourceName":36,"sourceUrl":36,"status":37,"seoTitle":36,"seoDescription":36,"canonicalUrl":36,"isFeatured":38,"sno":39,"sortOrder":40,"publishedAt":41,"updatedAt":42,"createdAt":43},"e9b80a51-876b-43f6-a2fb-e5c8e9c1acaa","article","HTTP 103 Early Hints：网页还没返回，服务器为什么先说一声","http-103-early-hints-explained","HTTP 103 Early Hints 允许服务器在最终响应之前先发送 Link 预加载和预连接提示。本文解释它与 HTTP\u002F2 Push 的差异、适合的资源、错误提示的代价，以及如何用真实指标判断它是否有效。","网页打开时，用户感受到的第一件事往往不是最终内容，而是“等了多久才开始动”。服务器可能需要查询数据库、渲染模板或等待后端服务，但浏览器其实已经知道某些资源很重要：CSS、字体、主脚本。HTTP 103 Early Hints 允许服务器在最终响应准备好之前，先发一条提示，让客户端提前准备这些资源。[RFC 8297](https:\u002F\u002Fwww.rfc-editor.org\u002Finfo\u002Frfc8297\u002F)\n\n![浏览器请求与服务器响应示意图](https:\u002F\u002Fcommons.wikimedia.org\u002Fwiki\u002FSpecial:FilePath\u002FHttp-request.png)\n\n它的关键不是“提前返回半个 HTML”，而是发送一个临时的信息响应。后面仍然要有真正的最终响应，例如 `200 OK` 或 `304 Not Modified`。如果把 103 当成最终结果，缓存、权限和内容完整性都会变得混乱。\n\n## 普通请求为什么会浪费等待时间\n\n一次页面请求可以粗略分成几段：建立连接、发送请求、等待服务器开始响应、下载 HTML、解析 HTML、发现 CSS 和脚本、再下载这些资源。即使服务器能在 200 毫秒后返回 HTML，浏览器也可能要等解析到 `\u003Clink>` 或 `\u003Cscript>` 才知道下一批资源在哪里。\n\n如果服务器在生成页面之前就知道关键资源，可以把等待阶段利用起来：\n\n```http\nHTTP\u002F1.1 103 Early Hints\nLink: \u003C\u002Fstyles\u002Fmain.css>; rel=preload; as=style\nLink: \u003C\u002Fapp.js>; rel=preload; as=script\n\nHTTP\u002F1.1 200 OK\nContent-Type: text\u002Fhtml\n\n\u003C!doctype html>\n...\n```\n\n第一段不是页面正文，而是给客户端的“可能即将用到这些资源”的提示。最终响应通常仍会带上相应的 `Link` 信息或在 HTML 中引用资源。客户端应该把它当作预加载建议，而不是不可撤销的承诺。\n\n## 103 到底提前了什么\n\n最常见的是 `Link` 响应头，配合 `preload`、`preconnect` 等关系使用：\n\n- `preload`：尽早下载一个当前页面很可能需要的资源。\n- `preconnect`：提前建立到另一个源的连接，减少后续握手等待。\n- `dns-prefetch`：提前进行域名解析，但节省的时间通常小于完整连接准备。\n\nEarly Hints 的价值取决于“提示是否正确”和“等待是否足够长”。如果 HTML 很快就返回，提前提示可能几乎没有收益；如果服务端渲染要等较久，提前建立连接和下载关键 CSS 才可能改善首屏。\n\n```mermaid\nsequenceDiagram\n    participant B as 浏览器\n    participant S as 服务器\n    B->>S: GET \u002Fhome\n    S-->>B: 103 Early Hints\n    B->>CDN: 预加载 CSS \u002F 建立连接\n    S-->>B: 200 OK + HTML\n    B->>CDN: 继续使用已准备的资源\n    CDN-->>B: CSS \u002F JS \u002F 字体\n```\n\n## 它和 HTTP\u002F2 Server Push 有什么不同\n\nServer Push 是服务器主动把资源推给客户端；Early Hints 主要是在最终响应前告诉客户端“你可以自己开始准备”。后者让浏览器保留更多控制权，浏览器可以根据缓存、优先级和当前网络决定是否真的加载。\n\n这也意味着 Early Hints 不会神奇地消除网络成本。预加载了错误资源，可能抢占真正重要资源的带宽；预加载了用户最终不会看到的页面资源，反而增加浪费。性能优化不是把所有文件都提前下载，而是把关键路径上确定性高、等待成本大的资源往前移动。\n\n## 为什么不能随便发一个 103\n\n### 1. 资源提示必须接近事实\n\n如果页面根据用户身份、实验分组或地区加载不同脚本，边缘缓存层可能并不知道最终会使用哪一份资源。此时过于具体的 Early Hints 可能造成错误预加载，甚至引入缓存键设计问题。\n\n### 2. 提示不能当作最终安全边界\n\n103 只表示服务器预计最终响应会包含相关字段。客户端不能把它当成权限授予，也不能因为收到了一个预加载 URL 就认为资源一定属于最终页面。最终响应仍然要经过正常的缓存、CSP、完整性和权限处理。\n\n### 3. 中间设备可能改变体验\n\n浏览器、CDN、反向代理和 HTTP\u002F2\u002FHTTP\u002F3 链路的支持情况都可能不同。部署时不能只看源站日志，需要确认真实用户是否收到 103、资源是否真的提前开始，以及带宽是否被错误预加载占用。\n\n## 怎样判断它真的有效\n\n不要只比较服务器的 TTFB。应同时观察：\n\n- 关键 CSS 和字体的请求开始时间是否提前。\n- First Contentful Paint、Largest Contentful Paint 是否改善。\n- 首屏资源的缓存命中率和取消下载比例。\n- 移动网络下的额外流量与并发连接数。\n- 页面分支变化时，错误提示的比例。\n\n一个稳妥的落地方式是先只提示确定性最高的 CSS，再做小流量实验。对动态页面，宁愿少预加载一两个资源，也不要把整个资源清单都塞进 103。\n\n## 一句话带走\n\nEarly Hints 做的是“把浏览器已经迟早要做的准备提前一点”，不是提前发送页面答案。它最适合解决服务器生成内容时的空档，但收益建立在资源判断准确、链路支持良好和测量完整的基础上。\n\n## 延伸阅读\n\n- [RFC 8297：Early Hints](https:\u002F\u002Fwww.rfc-editor.org\u002Finfo\u002Frfc8297\u002F)\n- [HTTP 请求与响应示意图](https:\u002F\u002Fcommons.wikimedia.org\u002Fwiki\u002FFile:Http-request.png)","\u002Fuploads\u002F2026-08-09\u002Fe05de330-4729-47eb-b9b3-a0a6bd9ba03e.jpg",[],[],"Foundit","https:\u002F\u002Ffoundit.cn","f39339b1-aaa6-4e86-b0c2-a6e6a21113b5",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31],{"id":24,"name":25,"slug":26},"144abe77-0dc6-4f66-a176-20bddb1c0bfa","编程","coding",{"id":28,"name":29,"slug":30},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":32,"name":33,"slug":34},"4c2bbea6-eab7-40a8-8447-1de478ff7749","分析","analyse","资料来源",null,"published",false,65,0,"2026-08-09T00:00:00.000Z","2026-08-09T12:49:03.520Z","2026-08-09T12:13:27.721Z",[45,54,63],{"id":46,"type":6,"title":47,"slug":48,"summary":49,"coverUrl":50,"authorName":14,"sno":51,"publishedAt":52,"createdAt":53},"62724dbd-ce49-4be9-afa9-4ba127513a62","语音搜索一定先变成文字吗？AI 开始绕过转写这一步","speech-to-retrieval-without-transcription","传统语音搜索先把声音转成文字，再拿文字查资料，一次听错就可能让搜索方向完全跑偏。Speech-to-Retrieval 尝试直接把语音与相关文档映射到同一个语义空间。本文用蒙克名画的例子讲清新旧架构及其边界。","\u002Fuploads\u002F2026-09-08\u002Fe1173842-1ec4-48f3-8349-240fc2d78197.jpg",50,"2026-08-30T00:00:00.000Z","2026-08-14T03:06:11.525Z",{"id":55,"type":6,"title":56,"slug":57,"summary":58,"coverUrl":59,"authorName":14,"sno":60,"publishedAt":61,"createdAt":62},"0999bb14-a97c-4003-84e7-61ad2da998e0","文件删除以后去了哪里？为什么有时还能恢复？","where-deleted-files-go-data-recovery","普通删除往往只是移除文件系统里的索引并把空间标记为可重用，数据本身未必立即消失；SSD 的 TRIM、磨损均衡与加密又让情况更加复杂。本文区分回收站、删除、覆盖和安全清除，说明何时应停止写入设备。","\u002Fuploads\u002F2026-09-08\u002Fb7222764-de75-4863-8679-0a94a8965af3.jpg",51,"2026-08-20T00:00:00.000Z","2026-08-14T03:06:15.710Z",{"id":64,"type":6,"title":65,"slug":66,"summary":67,"coverUrl":68,"authorName":14,"sno":69,"publishedAt":70,"createdAt":71},"55f42805-a25a-4ce3-89d9-121b9a268a8f","0.1＋0.2 为什么不等于 0.3？计算机真的算错了吗？","why-point-one-plus-point-two-not-point-three","许多十进制小数无法用有限位二进制精确表示，计算机只能保存最接近的值。微小误差在显示时常被隐藏，却会在比较、累计和金额计算中冒出来。本文用三分之一的类比讲清浮点数，并给出可靠的处理原则。","\u002Fuploads\u002F2026-09-08\u002Ffd3a7daf-2a2c-4ef0-8f57-38f1d9de962c.jpg",54,"2026-09-06T00:00:00.000Z","2026-08-14T03:06:15.129Z"]