HTTP/2推送之难,远超想象(4)

Chrome会拒绝被推送已经位于推送缓存中的项。Chrome会使用PROTOCOL_ERROR而不是CANCEL或REFUSED_STREAM进行拒绝,但这并不是个什么大问题(问题描述)。然而Chrome不会拒绝已经位于HTTP缓存中的项。听说这个问题已经修复了,但我还没进行测试(问题描述)。

Safari会拒绝被推送已经位于推送缓存中的项,但前提是按照缓存报头(例如max-age)的设置来看,推送缓存中的项依然是“新鲜的”,除非用户手工点击了“刷新”。这一点与Chrome有所不同,但我觉得也不算“错”。然而与Chrome类似,Safari不会拒绝已经位于HTTP缓存中的项(问题描述)。

Firefox会拒绝被推送已经位于推送缓存中的项,但随后它会丢弃已经位于推送缓存中的项,什么都不留下!这使得缓存机制变得极为不可靠,难以辩解(问题描述,含视频)。此外Firefox也不会拒绝已经位于HTTP缓存中的项(问题描述)。

Edge不会拒绝被推送已经位于推送缓存中的项,但会拒绝已经位于HTTP缓存中的项。

建议

遗憾的是,就算浏览器提供了完美的支持,依然会在收到取消信息之前浪费带宽和服务器I/O。此时可以通过缓存摘要(Cache digest)提前告诉服务器哪些内容已经缓存。

同时也可以使用Cookie来追踪是否已经将可缓存的资源推送给用户。然而由于浏览器的“心血来潮”,项可能从HTTP缓存中消失,但Cookie是可以持久保存的,因此Bookie的存在并不一定意味着项依然位于用户的缓存中。

除了新鲜度,推送缓存中的项还可以使用HTTP语义进行匹配

上文介绍过,在对推送缓存进行匹配时会忽略内容的新鲜度(no-store和no-cache项就是这样匹配的),但其实也可以使用其他匹配机制。我测试过POST请求和Vary: Cookie。

更新:规范中提到,推送的请求“必须是,必须是,并且必须不能包含请求主体”,之前我漏掉了这些规定。POST请求不能算是“安全的”,因此浏览器应当拒绝POST。

Chrome - 糟糕支持

Safari - 部分支持

Firefox - 糟糕支持

Edge - 糟糕支持

Chrome可接受POST推送流,但似乎无法使用这种流(问题描述)。在匹配已推送项时,Chrome还会忽略Vary报头(问题描述),但问题描述中提到可以配合QUIC使用。

Firefox会拒绝推送的POST流,然而在匹配已推送项时,Firefox会忽略Vary报头(问题描述)。

Edge也会拒绝推送的POST流,但也会忽略Vary报头(问题描述)。

Safari与Chrome类似,可接受POST推送流,但似乎无法使用(问题描述)。但Safari会遵守Vary报头,是唯一一个有此行为的浏览器。

建议

其实我挺难过,除了Safari,其他浏览器在处理推送项时都没有遵守Vary报头。这意味着我们可以推送某些专门针对某一个用户的JSON,随后该用户注销,另一个用户登录,但如果之前为上一个用户推送的JSON尚未使用,后来的用户将能看到这些内容。

如果要推送只适用于一个用户的数据,请在响应中包含预期用户的ID。如果随后发现ID与预期不符,可以再次发起请求(这样以前推送的内容将消失)。

在Chrome中,也可以在用户注销时使用Clear site data报头。此外也可以通过终止HTTP/2连接的方式清理推送缓存中的项。

还可以为其他源推送项

作为developers.google.com/web的负责人,我们可以让自己的服务器推送包含Android.com所需任何内容的响应,并设置缓存一年的时间。一个简单的Fetch就足以将其放入HTTP缓存。随后如果我们的访客访问了android.com,他们就可以看到用粉红色Comic Sans字体显示的“NATIVE SUX – PWA RULEZ(原生弱爆了 – PWA才是王道)”字样,或我们希望显示的任何内容。

当然我们不会那么做的,毕竟我们那么热爱Android,我就是这么一说…… Android:如果你搞砸了Web,我们会给你好看的。

好吧,开玩笑而已,但上述情况在技术上是可以实现的。实际上不能为任何其他源推送资源,但可以针对连接的“权威”源进行推送。

查看developers.google.com的证书会发现,它是所有Google源,包括android.com的权威。

https://youtu.be/i9uXp64KUcw

在Chrome中查看证书信息

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/90e04b79b9d458bc3a9d0955b0bda1c8.html