关于 http2 下 push 接口请求的正确姿势

CarterLi

今天听👆哥说(吹)到他们网站用HTTP2推送接口请求极大的加快的网站访问速度。其实我在去年研究 HTTP2_push 时就想到了这个情形。

是否需要 push 静态资源是有疑问的:由于缓存的存在,你不能确保客户端真的需要这个文件。虽然浏览器可以主动阻止 PUSH 帧的发送,但是对于已发出的帧无能为力

接口请求就不存在这个情况:因为它们都不会被(被开发者禁掉了)浏览器缓存,每次打开页面都需要重新加载。所以推送接口请求总是正确的选择。

Nginx 1.13.9 就增加了 HTTP2_Push 支持。Nginx 开启 HTTP2 推送有两种方法。

http2_push 指令

强制推送某 URL。用法就是:

http2_push URL;

这个 URL 可以是反向代理的 API 请求地址。这样推送的 HTTP2 帧可以直接被浏览器使用。

clipboard.png

可以看到,对于服务端推送的帧,浏览器会等到实际有请求时再去解析。

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 头,同时会预加载这个资源。

clipboard.png

可以看到,对于服务端推送的帧,浏览器会在接收完毕后立即解析

至于哪种情况更好,各位读者自己取舍。

示例中用到的代码

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);

参考链接:

  1. https://bugs.chromium.org/p/c...
  2. https://developer.mozilla.org...
  3. https://w3c.github.io/preload/
  4. https://jakearchibald.com/201...

PS:http2_push_preload 的更高端用法可能是使用 njsopenresty 动态添加 Link 头实现动态推送资源(例如根据不同的用户推送不同资源)
PS2:如果使用 Link 头推送 API 资源,一定要添加 crossorigin 参数,否则浏览器不会使用收到的 PUSH 数据
PS3:经测试就算加了 crossorigin 头 Chrome 也不一定会用收到的 PUSH 数据(而 Firefox 会,可能是 bug),使用 http2_push 是最保险的方式

阅读 5.2k

我大EOI前端
[链接] 虽然公司尚小,但是志向不小
1.3k 声望
99 粉丝
0 条评论
1.3k 声望
99 粉丝
文章目录
宣传栏