HTTP/2 Server Push

封面的像素狗参考小圓柴

HTTP/2 Server Push 是什么?

Ponzu CMS 是一个看起来不错的 Headless CMS,除了简陋的 API。其允许对象之间创建引用关联,但是由于其底层基于 BlotDB,一个 Key-Value Store,并不支持相关的查询。

A foreign key as a URL path?! Am I crazy? No! For the purpose Ponzu serves, this structure works quite well, especially given its creation was specifically tuned for HTTP/2 features such as “Request/Response Multiplexing” and “Server Push.”1

查询内容可以得到内容本身,其中的引用字段呈现为 RESTful URL 的形式。作者的期望是,服务端直接将需要的内容通过 Server Push 一同发送给客户端,而不必等待再次请求。

关于 HTTP/2 Server Push

HTTP/2

先说 HTTP/2,HTTP/2 的前身是 Google 的 SPDY 协议,其在多个浏览器上得到了很好的支持。后来 IEFT 基于 SPDY 进行了 HTTP/2 标准化。

SPDY(发音为「speedy」)是一个由 Google 主导的研究项目发明的HTTP替代协议。SPDY 一开始主要关注降低延迟,采用了 TCP 通道,但是使用了不同的协议来达到此目的。2

HTTP/2 的主要目标是通过支持完整的请求与响应复用来减少延迟,通过有效压缩 HTTP 标头字段将协议开销降至最低,同时增加对请求优先级和服务器推送的支持。3

从 HTTP/1.x 到 HTTP/2,大部分适配工作是不需要开发者区进行额外操作的,但是 HTTP/2 Push 有所不同。

Server Push

HTTP/2引入了服务器推送,即服务端向客户端发送比客户端请求更多的数据。这允许服务器直接提供浏览器渲染页面所需资源,而无须浏览器在收到、解析页面后再提起一轮请求,节约了加载时间。2

Server Push 针对与当前请求同源的内容,举个例子的话,index.html 有必要的外部 CSS/JS 以及一些图片等等资源需要请求,既然迟早都要请求,那么服务端返回 index.html 的时候,一同(先一步)把需要的资源文件 Push 给客户端,客户端就不必再次发送多个请求,节省很大一笔时间开销。

那么回到一开始的问题上,假设服务端获得了一条 Post,其有对 User 的引用,那么服务端除了在返回之前 Push 一个 User 之外,并需要多做什么,而客户端可以直接请求对应的 User 内容,但是因为已经先一步 Push 过来了,所以这里就不需要再发送一个请求过去了。当然请求的次数本身并没有减少,但是少了一个传输的环节,不必再有一个请求千里迢迢从客户端赶到服务端然后等待返回了。

Golang 的话本身就自带了 Push 的实现,此外还有一个 http2 包可以使用。

// ...

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.(http.Pusher).Push("/favicon.ico", nil)
    w.(http.Pusher).Push("/dog.png", nil)

    w.Header().Set("Content-Type", "text/html")
    w.Write([]byte(`<img src="dog.png" />`))
})

// http.ListenAndServeTLS(...)

Server Push 需要启用 HTTPS,本地的话可以自己签发一张证书简单试一下。

可以看到截图中的「Push」
可以看到截图中的「Push」

  1. https://docs.ponzu-cms.org/References/Overview/ “References in Ponzu” [return]
  2. https://zh.wikipedia.org/wiki/HTTP/2 “HTTP/2 - 维基百科,自由的百科全书” [return]
  3. https://developers.google.com/web/fundamentals/performance/http/2/?hl=zh-cn “HTTP/2 简介 | Web Fundamentals | Google Developers” [return]