HTTP/2 的服务器推送(Server Push)是一种允许服务器在客户端请求之前主动发送资源的技术。这可以显著提高性能,特别是对于那些客户端稍后肯定会请求的资源(如 CSS、JavaScript、图片等)。
HTTP/2 服务器推送的原理
-
客户端请求: 客户端像往常一样向服务器发送一个请求(例如,请求一个 HTML 页面)。
-
服务器响应和推送:
- 服务器首先发送对初始请求的响应(例如,HTML 内容)。
- 紧接着,服务器 预测 客户端将需要哪些额外的资源(例如,HTML 中引用的 CSS 和 JavaScript 文件)。
- 服务器主动创建 推送流(Push Stream),并在这些流上发送预测的资源,而无需等待客户端的显式请求。
- 服务器发送一个特殊的
PUSH_PROMISE帧,其中包含推送资源的请求头信息(例如,URL、方法等)。这告诉客户端:“我将要推送这个资源,你做好准备。”
-
客户端处理:
- 客户端收到初始响应(例如,HTML)。
- 客户端解析 HTML,发现对 CSS 和 JavaScript 的引用。
- 客户端 检查 是否已经收到了这些资源的
PUSH_PROMISE帧。 - 如果已经收到,客户端会使用推送流中的数据,而无需再次向服务器发送请求。
- 如果没有收到,客户端会像往常一样发送对这些资源的请求。
关键点:
- 服务器推送是 预测性 的。服务器根据经验或配置来猜测客户端可能需要的资源。
- 客户端可以 拒绝 推送的资源。如果客户端已经缓存了资源,或者由于某种原因不需要它,它可以发送一个
RST_STREAM帧来取消推送流。 - 服务器推送必须遵循 同源策略。服务器只能推送与初始请求相同来源的资源。
PUSH_PROMISE帧非常重要。它允许客户端在解析 HTML 之前 就知道哪些资源将被推送。
前端需要做什么
从前端开发的角度来看,利用 HTTP/2 服务器推送通常 不需要 编写特殊的 JavaScript 代码。主要工作是在服务器端配置。以下是前端可以做的一些事情:
-
优化资源依赖关系:
- 确保 HTML 中引用的资源(CSS、JavaScript、图片等)是 真正 需要的,并且按照正确的顺序加载。
- 使用
<link rel="preload">或<link rel="prefetch">来提示浏览器预加载或预取资源。这可以与服务器推送结合使用,但它们是不同的机制。
-
处理推送的资源(可选):
- 虽然通常不需要特殊处理,但如果需要,你可以使用
fetch()API 或XMLHttpRequest来监听PUSH_PROMISE帧或处理推送流。但这通常是比较高级的用法,大多数情况下不需要。
- 虽然通常不需要特殊处理,但如果需要,你可以使用
-
监控和测试:
- 使用浏览器的开发者工具(例如,Chrome DevTools 的 Network 面板)来检查服务器是否正确推送了资源,以及客户端是否正确使用了它们。
- 测试不同网络条件下的性能,以确保服务器推送真正带来了好处。
服务器端配置(示例)
服务器推送的配置取决于你使用的 Web 服务器。以下是一些常见服务器的示例:
-
Node.js (with
http2module):const http2 = require('http2'); const fs = require('fs'); const server = http2.createServer(); server.on('stream', (stream, headers) => { const path = headers[':path']; if (path === '/') { // 1. 发送 index.html stream.respondWithFile('./index.html', { 'content-type': 'text/html' }); // 2. 推送 style.css (假设它在 index.html 中被引用) stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => { if (err) throw err; pushStream.respondWithFile('./style.css', { 'content-type': 'text/css' }); }); // 2. 推送 index.js (假设它在 index.html 中被引用) stream.pushStream({ ':path': '/index.js' }, (err, pushStream) => { if (err) throw err; pushStream.respondWithFile('./index.js', { 'content-type': 'text/css' }); }); // (可以推送更多资源) } else if (path === '/style.css') { //常规的/style.css 请求 stream.respondWithFile('./style.css', { 'content-type': 'text/css' }); } else if(path === '/index.js'){ stream.respondWithFile('./index.js', { 'content-type': 'text/css' }); } }); server.listen(8080); -
Apache (with
mod_http2):<IfModule http2_module> Protocols h2 http/1.1 H2Push on H2PushResource /css/style.css H2PushResource /js/script.js </IfModule>
可以在 .htaccess文件中或者在主配置文件中配置.
-
Nginx (with
http2_pushdirective):http { server { listen 443 ssl http2; server_name example.com; ssl_certificate /path/to/certificate.pem; ssl_certificate_key /path/to/private-key.pem; location / { root /path/to/your/website; http2_push /css/style.css; http2_push /js/script.js; # (可以推送更多资源) index index.html; } } }
使用 HTTP/2 协议的网站地址前缀
使用 HTTP/2 协议的网站地址前缀仍然是 https://。HTTP/2 是 HTTP 协议的升级版,但它仍然建立在 TLS/SSL 加密连接之上。因此,你需要一个有效的 SSL 证书才能使用 HTTP/2。
总结
- HTTP/2 服务器推送是一种强大的性能优化技术,但它主要依赖于服务器端的配置。
- 前端开发人员通常不需要编写特殊的代码来利用服务器推送,但可以优化资源依赖关系和监控推送效果。
- 使用 HTTP/2 的网站仍然使用
https://前缀。 - 确保你的服务器和客户端都支持 HTTP/2。大多数现代浏览器和 Web 服务器都已经支持。
如何检查网站是否使用 HTTP/2
-
浏览器开发者工具:
- 打开 Chrome DevTools (F12 或右键 -> 检查)。
- 切换到 "Network" 面板。
- 刷新页面。
- 在 "Protocol" 列中,你应该会看到 "h2"(表示 HTTP/2)或 "http/1.1"。
-
在线工具:
- 有一些在线工具可以检查网站是否使用 HTTP/2,例如 HTTP/2 Check。
如果你的网站仍然使用 HTTP/1.1,你可能需要升级你的 Web 服务器或联系你的托管服务提供商。