https://blog.csdn.net/textdemo123/article/details/103417638
https://nullget.sourceforge.io/?q=node/885
关于golang:HTTP2服务器推送的第一次尝试 - 乐趣区 (lequ7.com)
HTTP/2旨在解决HTTP/1.x的许多缺陷。现代web页面使用许多资源:HTML、样式表、脚本、图像等等。
在HTTP/1.x中,必须显式地请求这些资源中的每一个。这可能是一个缓慢的过程。
浏览器从获取HTML开始,然后在解析和计算页面时逐步了解更多资源。由于服务器必须等待浏览器发出每个请求,因此网络通常处于空闲状态且未充分利用。
为了提高延迟,HTTP/2引入了服务器推送,它允许服务器在显式请求资源之前将资源推送到浏览器。
服务器通常知道页面将需要的许多额外资源,并且可以在响应初始请求时开始推送这些资源。这允许服务器充分利用空闲的网络并提高页面加载时间
在协议层,HTTP/2服务器推送由push-PROMISE帧驱动。PUSH_PROMISE描述服务器预测浏览器将在不久的将来发出的请求。一旦浏览器收到推送承诺,它就知道服务器将交付资源。如果浏览器稍后发现它需要此资源,它将等待推送完成,而不是发送新请求。这减少了浏览器在网络上等待的时间。
server push 在net/http 包里面实现
Go1.8引入了对从http.Server推送响应的支持。如果正在运行的服务器是HTTP/2服务器,并且传入连接使用HTTP/2,则此功能可用。在任何HTTP处理程序中,都可以通过检查HTTP.ResponseWriter是否实现了新的HTTP.Pusher接口来断言它是否支持服务器推送。
例如,如果服务器知道需要app.js来呈现页面,则处理程序可以在http.Pusher可用时启动推送:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if pusher, ok := w.(http.Pusher); ok {
// Push is supported.
if err := pusher.Push("/app.js", nil); err != nil {
log.Printf("Failed to push: %v", err)
}
}
// ...
})
Push调用为/app.js创建一个合成请求,将该请求合成为Push-PROMISE框架,然后将合成请求转发给服务器的请求处理程序,后者将生成Push响应。
Push的第二个参数指定了Push-PROMISE中要包含的附加头
例如,如果对/app.js的响应在接受编码上有所不同,那么PUSH_PROMISE应该包含一个接受编码值:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if pusher, ok := w.(http.Pusher); ok {
// Push is supported.
options := &http.PushOptions{
Header: http.Header{
"Accept-Encoding": r.Header["Accept-Encoding"],
},
}
if err := pusher.Push("/app.js", options); err != nil {
log.Printf("Failed to push: %v", err)
}
}
// ...
})
另
package main
import (
"html/template"
"log"
"github.com/gin-gonic/gin"
)
var html = template.Must(template.New("https").Parse(`
<html>
<head>
<title>Https Test</title>
<script src="/assets/app.js"></script>
</head>
<body>
<h1 style="color:red;">Welcome, Ginner!</h1>
</body>
</html>
`))
func main() {
r := gin.Default()
r.Static("/assets", "./assets")
r.SetHTMLTemplate(html)
r.GET("/", func(c *gin.Context) {
if pusher := c.Writer.Pusher(); pusher != nil {
// use pusher.Push() to do server push
if err := pusher.Push("/assets/app.js", nil); err != nil {
log.Printf("Failed to push: %v", err)
}
}
c.HTML(200, "https", gin.H{
"status": "success",
})
})
// Listen and Server in https://127.0.0.1:8080
r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
}
Go是反对HTTP2的且HTTP2须要应用SSL/TLS即HTTPS
- 服务器推送不要滥用,仅推送影响该页面展现的要害资源,毕竟前端的懒加载曾经非常成熟。
- 浏览器可能对资源进行缓存,对于曾经缓存了的资源持续推送没有意义,所以这种场景下要防止二次推送。