技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTNET

浅谈 HTTP/2 Server Push(Chrome 已移除支持)

所属馆藏
NET Protocol
文件格式
Markdown
原始路径
NET Protocol/23-浅谈 HTTP 2 Server Push (chrome 已废弃支持)
本文目录8 个章节
  1. Server Push 是什么?
  2. 推什么?
  3. 怎么推?
  4. Demo:推送 API 的历史效果
  5. 如何验证 Server Push?
  6. 跨 Origin 推送
  7. Server Push 的现状与替代方案
  8. 总结

浅谈 HTTP/2 Server Push(Chrome 已移除支持)

Category(分类): NET Protocol Status: 未知

本文记录 HTTP/2 Server Push 的设计目的、工作流程和历史实践。需要特别说明:Server Push 仍然存在于 HTTP/2 的协议规范中,但 Chrome 已移除浏览器端支持,现代浏览器和 CDN 对它的支持也非常有限。新项目不应把 Server Push 作为主要性能优化方案。

原文发布时间:2019-04-16

参考文章:

Server Push 是什么?

HTTP/2 在 HTTP/1.1 持久连接的基础上引入了二进制帧、流和多路复用:

  • 持久连接允许客户端和服务端在同一条 TCP 连接上发送多个请求和响应;
  • HTTP/1.1 管道化允许客户端在收到前一个响应前继续发送后续请求,但响应必须按顺序返回;
  • HTTP/2 使用多个 Stream,并把数据拆成 Frame 交错传输,减少 HTTP 层面的队头阻塞。

Server Push 的核心思想是:客户端还没有明确请求资源时,服务端根据已知上下文,主动发送该资源的响应。

它主要解决两个问题:

  1. 服务端应该推送什么资源;
  2. 服务端如何让客户端知道资源即将被推送。

Server Push 不是浏览器 JavaScript API,而是 HTTP/2 协议层的能力。客户端仍然可以拒绝、取消或忽略服务端推送。

推什么?

推送静态资源

在 HTTP/1.x 时代,一些网站会把 CSS 和 JavaScript 内联到 HTML 中,以减少额外请求。Server Push 可以让服务端在返回 HTML 的同时,主动推送 HTML 可能引用的资源。

HTTP/2 推送静态资源示意图

上图是概念示意:服务端除了返回 HTML,还主动推送样式表或脚本。理论上可以减少以下等待:

  • 浏览器接收并解析 HTML,发现资源引用的等待时间;
  • 浏览器发送资源请求以及服务端处理该请求的时间。

但这并不代表推送静态资源一定有收益:

  1. HTML 通常不大,浏览器可能很快发现位于文档前部的 CSS 和脚本引用;
  2. HTTP/2 已经可以在同一条连接上并发传输多个请求,额外请求的成本通常比 HTTP/1.1 小;
  3. 如果资源已经在浏览器缓存中,重复推送会浪费带宽;
  4. 服务端可能在客户端决定不需要资源之前就发送了大量数据;
  5. CDN、代理和浏览器支持情况会直接影响推送是否真正生效。

因此,Server Push 需要结合缓存状态和真实访问数据使用,不能简单地把所有 CSS、JS、图片都主动推送。

推送 API 响应

历史上有人尝试推送 API 响应,因为:

  • 浏览器通常较早发现 HTML 中的 CSS 和脚本引用;
  • API 请求可能要等到 JavaScript 下载、解析并执行后才会发起;
  • 一些 API 响应的缓存时间比静态资源短,或者需要结合当前页面上下文计算。

但推送 API 比推送静态资源复杂得多。API 可能依赖:

  • 查询参数;
  • Cookie;
  • Authorization
  • Accept-Language
  • Vary 首部;
  • 用户权限和个性化状态。

如果推送了错误用户、错误参数或客户端不会使用的响应,可能造成隐私问题、缓存错误和带宽浪费。只有当服务端能够准确预测请求,并确认响应适合当前客户端时,才有考虑推送的价值。

Server Push 的限制

服务端推送的承诺请求必须满足 HTTP/2 的协议限制。通常需要满足:

  • 请求方法是安全的;
  • 响应适合缓存;
  • 请求不能带请求体;
  • 服务端对目标资源具备权限和权威性;
  • 响应不能因为用户权限或请求上下文而被错误地复用。

实际应用中最常见的是 GET 或 HEAD 请求,但不能把 Server Push 简化成“任意 GET 都可以推”。是否能推送,还要考虑缓存语义、请求头、认证信息和客户端策略。

怎么推?

Server Push 的基本原理可以概括为:服务端先代替客户端创建一个请求,再把响应推给客户端。

假设客户端请求 HTML,服务端判断其中会引用一个 CSS 文件。服务端可以发送 PUSH_PROMISE 帧,在其中描述一个承诺请求的请求头,并分配 Promised Stream ID,告诉客户端:

我准备在另一个流中发送这个资源的响应,你不需要再重复请求它。

之后,服务端在承诺的流中发送响应头和数据帧。客户端可以根据 Promised Stream ID 读取推送响应。

HTTP/2 PUSH_PROMISE 工作流程

PUSH_PROMISE 的发送时机

如果 HTML 中已经引用了 CSS,服务端通常应该先发送 PUSH_PROMISE,再发送包含该引用的 HTML 内容。否则,客户端可能先解析到资源引用并主动发送普通请求,之后才收到 Server Push,导致两者产生竞争。

典型顺序如下:

服务端 -> 客户端:PUSH_PROMISE(承诺推送 CSS)
服务端 -> 客户端:HTML 响应
服务端 -> 客户端:CSS 的响应头和数据

如果客户端先发起了 CSS 请求,服务端再发送 PUSH_PROMISE,推送可能失败或被客户端拒绝。

客户端取消推送

客户端收到 PUSH_PROMISE 后,可能发现:

  • 资源已经在缓存中;
  • 页面实际不会使用该资源;
  • 推送资源不满足当前请求上下文;
  • 客户端或浏览器策略禁止 Server Push。

此时客户端可以发送 RST_STREAM 取消对应的推送流。但服务端收到取消帧之前可能已经发送了部分数据,因此取消不一定能避免全部带宽浪费。这是协议交互中的正常竞争,不是实现 Bug。

服务端也不应假设客户端一定接受推送。客户端拒绝推送后,仍可能通过普通请求获取资源。

Demo:推送 API 的历史效果

为了测试 Server Push,原文使用过饿了么 PC 餐厅列表页面作为 Demo。以下时间线和截图属于当时的特定浏览器、网络、服务器和缓存环境,只能作为历史示例,不能代表今天的普遍效果。

在开启 Server Push 之前:

未开启 HTTP/2 Server Push 的时间线

使用 Server Push 推送页面 API 之后:

开启 HTTP/2 Server Push 的时间线

在该 Demo 中,页面总体加载时间、空闲时间和图片开始加载的时间有所改善。但单次 Demo 不能证明 Server Push 在所有环境都有收益,还应对以下指标进行对照测试:

  • 首次访问和重复访问;
  • 有缓存和无缓存;
  • 不同网络延迟和带宽;
  • 推送命中率和取消率;
  • 实际传输字节数;
  • 页面交互可用时间;
  • CDN、代理和浏览器对推送的支持情况。

推送 API 还需要处理查询参数、Cookie、认证头和个性化响应,因此比推送公共静态资源复杂得多。服务端必须确保推送内容不会被错误地复用于其他用户。

原文提到的 Sopush 是当时用于探索 Server Push 的 HTTP/2 服务端实现。相关工程和 Demo 属于历史背景,当前使用前应确认其维护状态和浏览器兼容性。

如何验证 Server Push?

在支持 Server Push 的浏览器或客户端中,可以在 Network 面板中观察 Push 相关标识,或通过 HTTP/2 帧日志确认是否出现:

  • PUSH_PROMISE
  • 推送流的响应头;
  • 推送流的数据帧;
  • 客户端发送的 RST_STREAM

历史浏览器中 Server Push 的调试示意图

但 Chrome 的 chrome://net-internals/#http2 已经是过时的调试方式,现代环境可以考虑:

  • chrome://net-export/ 导出 NetLog;
  • 浏览器 DevTools 查看当前协议和请求信息;
  • Wireshark 分析 HTTP/2 帧;
  • nghttp2 等 HTTP/2 工具进行协议级测试;
  • 使用明确支持 Server Push 的专用客户端和服务器。

由于 Chrome 已移除 Server Push 支持,普通 Chrome 用户通常无法通过 Network 面板复现原文中的 Push 标识。

跨 Origin 推送

原文提到“只要证书匹配,就可以推送其他 Host 的资源”,这个说法不完整。

跨 Origin 推送除了证书 SAN 覆盖目标域名外,还需要满足:

  • 服务端对目标 Origin 具有权威性;
  • 连接协议、端口和 Origin 关系符合客户端安全策略;
  • 客户端允许连接复用和跨 Origin 推送;
  • 服务端正确设置请求中的 :authority 等字段;
  • 证书链、TLS、缓存和资源权限均验证通过。

因此,证书匹配只是必要条件之一,不代表任何 Host 的资源都可以被推送。实际项目通常优先推送同一 Origin 下的公共资源,并避免推送依赖用户身份的敏感响应。

Server Push 的现状与替代方案

Server Push 的设计目标是减少客户端发现资源和发起请求的等待,但实践中经常遇到缓存判断困难、带宽浪费、浏览器支持不足和服务端预测不准等问题。

Chrome 已经移除 Server Push,其他浏览器和中间网络设备的支持也不能假设一致。因此,新项目通常考虑以下替代方案:

  • 使用浏览器缓存和正确的 Cache-Control
  • 使用 <link rel="preload"> 提前声明关键资源;
  • 使用 103 Early Hints 提前发送资源提示;
  • 使用 HTTP/2 或 HTTP/3 的多路复用;
  • 优化 HTML、CSS 和 JavaScript 的加载顺序;
  • 通过 CDN、压缩、内容指纹和合理缓存降低资源加载成本。

这些方案通常更容易观测、控制和渐进式部署。

总结

HTTP/2 Server Push 的核心流程是:

  1. 客户端请求 HTML;
  2. 服务端通过 PUSH_PROMISE 描述即将推送的资源;
  3. 服务端在承诺的流中发送资源响应;
  4. 客户端根据缓存和策略接受、忽略或取消推送。

它曾经可以减少客户端发现资源和发起请求的等待,但也可能重复推送缓存内容、浪费带宽,或错误推送个性化数据。Server Push 仍然是 HTTP/2 的历史协议能力,但已经不适合作为现代浏览器环境下的默认优化手段。

参考规范:

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS