响应头里写 preload 有时不生效,哪几种关系类型在 HTTP 头里才可靠
资源预取写进页面标签还是写进 HTTP 响应头,哪几种关系才可靠生效的答案并不相同,两层的语义差别常被混为一谈。响应头在文档正文送达之前就已经被解析,时机更早,可支持的关系类型却更少。按 MDN 对 Link 头的说明,实践中多数 rel 链接类型放进 HTTP 头并不生效,真正可靠的是预连接与预加载两类。要判断该把哪些提示交给响应头,得先把这两层的差异摊开来看。
Link 头与页面标签的分工不同
页面里的 link 标签由 HTML 解析器读取,除了预取提示,还能承担样式表关联、图标声明等作用;Link 响应头只在文档层面给出链接关系,不接管这些标签自身的行为。语法上两者也不同:响应头里每个链接值要把 URI 用尖括号包裹,后面跟 rel 等参数,URI 中的非 ASCII 字符必须先做百分号编码,否则整条头字段可能被直接忽略。好处是它由服务端或边缘节点注入,不必改动 HTML 模板,对同一份文档的所有请求都一致生效。
多数 rel 放进响应头并不生效
预取类、模块预加载类、样式表类这些在标签里常见的关系,放进响应头后往往得不到预期处理。下表按可靠性分层。
| rel 类型 | 放进响应头是否可靠 | 说明 |
|---|---|---|
| preconnect | 可靠 | 提前完成域名解析与连接建立,对跨源资源收益直接 |
| preload | 可靠 | 提前发起指定资源的请求,需给出 as 与跨源属性 |
| prefetch | 不可靠 | 面向下一次导航的推测性下载,头部形式常被忽略 |
| modulepreload | 不可靠 | 语义依赖模块图,通常只在文档内声明才有效 |
| stylesheet | 不适用 | 标签形态才承担样式应用职责,头部声明不等于生效 |
| dns-prefetch | 不可靠 | 已被 preconnect 覆盖,头部形式缺少稳定支持 |
与 103 Early Hints 组合才有更早的窗口
Link 头的价值在于早,但早的程度取决于它在哪个阶段被发出。若服务端能在响应尚未组装完成时先下发 103 Early Hints 状态码,并把预连接与预加载的 Link 头放在这一批信息里,浏览器就能在等待正文的那段时间开始建立连接、拉取资源,等正式响应到达时部分请求已经完成。这层配合需要 Web 服务器与上游程序共同支持,任何一跳把它丢掉,效果就退化为普通响应头。
内容站首屏该提前取什么、怎么核对
值得放进响应头的资源有两个特征:跨源、且不在初始 HTML 的引用链上。首屏用到的字体文件、由脚本动态注入的关键样式、来自独立静态域的头像与图集入口,属于典型对象;已经写在页面里的图片和主样式表,浏览器自己会发现,重复预取只会增加无用请求。资源该由哪一层给出,取决于静态文件的产出方式:路径在构建阶段就确定的,写进模板标签更容易维护和审计;路径按访问者、按语言或按压缩策略在运行时才定的,交给响应头注入更省事,也避免模板里堆条件分支。
核对的方式要落到可观测的证据上。先抓一次真实响应,确认头字段里的 URI 是否带尖括号、是否完成百分号编码、as 与 crossorigin 是否齐备;再看浏览器网络面板中请求的发起原因,出现与预加载或早期提示相关的标记,才说明这条提示真的被消费。最后做一轮对照,同一页面分别用只写标签、只写响应头、两者结合三种排法各测多次,取分布而不是单点数值,避免把偶发的缓存命中读成优化效果。
常见问题
问:响应头里写预取没生效,通常是哪里出错?
答:先看三点,关系类型是否在可靠范围内,URI 有没有用尖括号包裹并做百分号编码,跨源资源是否补齐了 as 与 crossorigin。任一项缺失,浏览器都可能整条忽略。
问:既然响应头更强,是不是该把标签里的预取全部迁过去?
答:不建议一刀切。样式表关联、图标声明这类依赖标签语义的关系留在页面里,响应头只承担预连接与预加载,两层各司其职更稳定。
问:不用 103 Early Hints,Link 头还有意义吗?
答:有,但收益窗口变小。提示只能在正文到达后或首块响应时才被读到,能节省的时间主要落在连接建立阶段,对跨源资源的改善仍然可见。
问:怎么判断某条提示值不值得保留?
答:给它做一次单独关闭的对照测试,观察该资源的开始时间与首屏渲染指标是否退化。关掉后没有可辨变化的提示属于冗余,应清理掉。