今天听👆哥说(吹)到他们网站用HTTP2推送接口请求极大的加快的网站访问速度。其实我在去年研究 HTTP2_push 时就想到了这个情形。
是否需要 push 静态资源是有疑问的:由于缓存的存在,你不能确保客户端真的需要这个文件。虽然浏览器可以主动阻止 PUSH 帧的发送,但是对于已发出的帧无能为力。
接口请求就不存在这个情况:因为它们都不会被(被开发者禁掉了)浏览器缓存,每次打开页面都需要重新加载。所以推送接口请求总是正确的选择。
Nginx 1.13.9 就增加了 HTTP2_Push 支持。Nginx 开启 HTTP2 推送有两种方法。
http2_push 指令
强制推送某 URL。用法就是:
http2_push URL;
这个 URL 可以是反向代理的 API 请求地址。这样推送的 HTTP2 帧可以直接被浏览器使用。
可以看到,对于服务端推送的帧,浏览器会等到实际有请求时再去解析。
http2_push_preload 指令
Nginx 会解析预加载 Link 头动态的推送某 URL。用法为:
http2_push_preload on;
add_header Link "<URL>; rel=preload; as=TYPE; [crossorigin]";
URL 同上可为反代的 API 请求地址,但此时 TYPE 应为 fetch
,并且添加 crossorigin
参数。例如:
add_header Link "</restapi/shopping/v1/cities>; rel=preload; as=fetch; crossorigin";
这样的话,Nginx 同样会推送这个 API 资源。不同的是,浏览器由于收到了 preload_link
头,同时会预加载这个资源。
可以看到,对于服务端推送的帧,浏览器会在接收完毕后立即解析
至于哪种情况更好,各位读者自己取舍。
完
示例中用到的代码
setTimeout(() => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.onload = e => {
console.log(xhr.response);
document.querySelector('pre').textContent = JSON.stringify(xhr.response, null, 2);
};
xhr.open('GET', '/restapi/shopping/v1/cities');
xhr.send();
}, 1000);
参考链接:
- https://bugs.chromium.org/p/c...
- https://developer.mozilla.org...
- https://w3c.github.io/preload/
- https://jakearchibald.com/201...
PS:http2_push_preload 的更高端用法可能是使用 njs 或 openresty 动态添加 Link 头实现动态推送资源(例如根据不同的用户推送不同资源)
PS2:如果使用 Link 头推送 API 资源,一定要添加 crossorigin
参数,否则浏览器不会使用收到的 PUSH 数据
PS3:经测试就算加了 crossorigin
头 Chrome 也不一定会用收到的 PUSH 数据(而 Firefox 会,可能是 bug),使用 http2_push
是最保险的方式
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。