虽然很久之前看到Nginx更新支持Server Push的时候试了一波,不过没有应用下来。
现在逐步把几个小站都加上支持。

So,Server Push是啥?

举个栗子,客户端浏览器在请求页面(比如index.php)之后,还需要加载很多静态资源,比如CSS、JS、字体、图片等等,在这期间会产生很多请求,每次请求的握手和响应会造成延迟。
但如果使用了Server Push,相当于服务器可以主动推送所需要的资源给客户端,相当于打个包,在一次过程中直接丢给客户端,客户端就不需要再创建请求去获取这些文件。

但是有个限制,不支持跨域的Push(好像目前试下来是这样。

以实际来说的区别如图(由于已经部署丸了,就不单独切回去了,不是一个文件,主要关注TTFB时间。):

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

Server Push 不使用

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!使用Server Push

 

其实还是比较明显的,由于文件本身较小,之前的主要时间是被请求/等待时间占用,使用Server Push后,直接省掉了Request sent和Waiting的环节。

在大Chrome中,Server Push可以被区别出来,会标记为Push / Other。

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

啰嗦半天其实开启姿势肥肠简单,有两种方式可以做到。

其中止一,是在Nginx的配置文件(虚拟主机配置)location中,直接写入绑定的路径和Push的文件,可以Push多个文件。

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

这样的姿势,就可以在访问/test.html的时候,Push指定的文件了。

当然,不可能每次添加页面都去改vhost配置,需要一个优雅的方案,也就是第二种方法,在配置文件中加入:

http2_push_preload on;

这样我们就可以在应用端使用Header的方式,触发Nginx去Push文件。

这条配置支持放在http/server/location中,窝试了下放在server里reload好像没有生效,就直接放http了,实测OK。

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

修改完Nginx后,我们添加新页面时,只需要改页面而不用去动Nginx的配置。

So,我就以窝小站的首页为示例,首先如果你的首页还是HTML,你需要先改成PHP(或者其他应用),因为HTML的Meta Header好像Nginx不会响应。

之后访问页面,整理一下需要Push的资源,这里可以用Chrome开发者工具,以Sources筛选,可以比较全的抓到,需要注意目前窝试下来只有同域的可以被Push,Copy下Link然后丢到你熟悉的文本编辑工具做一下整理和字符替换。

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

 

使用PHP时,格式是这样的,举个例子:

header("Link: </index-assets/css/main.css>; rel=preload; as=style", false);

其中"/index-assets/css/main.css"是文件相对路径,最后的"false"是为了不覆盖header,也就是可以多次使用推送多个文件,"as=style"是文件的类型,注意这里有许多变量可选:

参考来源:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Preloading_content

一些主要可用的as 属性值列举如下:

audio: 音频文件。
document: 一个将要被嵌入到<frame>或<iframe>内部的HTML文档。
embed: 一个将要被嵌入到<embed>元素内部的资源。
fetch: 那些将要通过fetch和XHR请求来获取的资源,比如一个ArrayBuffer或JSON文件。
font: 字体文件。
image: 图片文件。
object: 一个将会被嵌入到<embed>元素内的文件。
script: JavaScript文件。
style: 样式表。
track: WebVTT文件。
worker: 一个JavaScript的web worker或shared worker。
video: 视频文件。

虽然什么文件都可以推送,但是不建议推送肥肠大的文件,要不会真丶拖慢DOM加载。

需要特别注意,这边有个坑,当你推送的文件是字体文件时,即使是同域文件,你也必须要指定另外一个跨域参数(其他方式可选):

header("Link: </index-assets/fonts/fontawesome-webfont.woff2?v=4.6.3>; rel=preload; as=font; crossorigin=anonymous", false);

如果没有加,就会遇到Chrome报Warning:

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

(A preload for 'https://www.tutugreen.com/index-assets/fonts/fontawesome-webfont.woff2?v=4.6.3' is found, but is not used because the request credentials mode does not match. Consider taking a look at crossorigin attribute.)(Text version for SEO)

这个文件就相当于被丢弃,之后页面即使再次请求也不会使用这个Push过来的版本:

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

之前就踩到了,以为是因为后面后version参数的原因,而且搜了下报错没有相关正确解释,后来看Mozilla的文档才发现有说明。

最后我这的代码看起来是这样的:

Server Push ON! - 启用Nginx HTTP/2的服务器推送, 真香!

总之大概过程就是这样了,结果测试发现以这样的方法可以推送最多10个文件,后面的好像不生效,窝之后再膜一膜看看。

当然,如果你患有懒癌,而且使用Wordpress,可以使用这个插件:https://wordpress.org/plugins/http2-server-push/

真丶全自动,点开就能。(当然Nginx部分还是需要自己配置的。)虽然Push的内容好像有点不全,但可以作为测试之类的23333。

另外如果懒癌2.0,完全不想配置Nginx配置的,那Cloudflare一定适合你,原生支持Header方式引导CDN去Push你想要的文件,即使你的Server不支持Push,Cloudflare也会完成相关过程。

Cloudflare文档传送门:https://blog.cloudflare.com/using-http-2-server-push-with-php/

 

如果有什么问题,肥肠欢迎留言!


升空的焰火,从下面看还是从侧面看?