Golang尝试官方示例中的HTTP2推送功能但未成功
Golang尝试官方示例中的HTTP2推送功能但未成功 代码示例如下:
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
pusher, ok := w.(http.Pusher)
if ok {
// 将资源推送到客户端
if err := pusher.Push("/styles.css", nil); err != nil {
log.Printf("推送失败: %v", err)
}
if err := pusher.Push("/app.js", nil); err != nil {
log.Printf("推送失败: %v", err)
}
}
// 返回HTML响应
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, "<html><head><title>HTTP/2 Push Example</title><link rel=\"stylesheet\" href=\"/styles.css\"><script src=\"/app.js\"></script></head><body><h1>Hello, HTTP/2 Push!</h1></body></html>")
})
log.Println("HTTP服务器正在监听 :8080")
log.Fatal(http.ListenAndServeTLS(":8080", "server.crt", "server.key", nil))
}
而 app.js 的内容是 console.log("Hello http2!")
但是当我使用 Chrome 访问 https://localhost:8080 时,app.js 文件中显示的内容却类似于:
<html><head><title>HTTP/2 Push Example</title><link rel=\"stylesheet\" href=\"/styles.css\"><script src=\"/app.js\"></script></head><body><h1>Hello, HTTP/2 Push!</h1></body></html>
这是怎么回事?
更有趣的是,如果我直接使用 Gin 框架的 HTTP/2 推送示例,它却能正常工作。
更多关于Golang尝试官方示例中的HTTP2推送功能但未成功的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang尝试官方示例中的HTTP2推送功能但未成功的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题在于你的HTTP/2推送代码逻辑。当浏览器请求/时,你同时推送了CSS和JS文件,但浏览器随后会正常请求这些资源,导致重复响应。
以下是修正后的示例:
func main() {
// 为静态资源添加单独的处理
http.HandleFunc("/styles.css", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/css")
fmt.Fprint(w, "body { background: #f0f0f0; }")
})
http.HandleFunc("/app.js", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/javascript")
fmt.Fprint(w, `console.log("Hello http2!");`)
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 只在HTTP/2连接上尝试推送
if r.ProtoMajor == 2 {
pusher, ok := w.(http.Pusher)
if ok {
// 推送前检查浏览器是否已缓存
if err := pusher.Push("/styles.css", &http.PushOptions{
Method: "GET",
Header: http.Header{
"Accept-Encoding": r.Header["Accept-Encoding"],
},
}); err != nil {
log.Printf("推送CSS失败: %v", err)
}
if err := pusher.Push("/app.js", &http.PushOptions{
Method: "GET",
Header: http.Header{
"Accept-Encoding": r.Header["Accept-Encoding"],
},
}); err != nil {
log.Printf("推送JS失败: %v", err)
}
}
}
// 返回HTML响应
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, `<html>
<head>
<title>HTTP/2 Push Example</title>
<link rel="stylesheet" href="/styles.css">
<script src="/app.js"></script>
</head>
<body>
<h1>Hello, HTTP/2 Push!</h1>
</body>
</html>`)
})
log.Println("HTTP服务器正在监听 :8080")
log.Fatal(http.ListenAndServeTLS(":8080", "server.crt", "server.key", nil))
}
关键修改:
- 为
/styles.css和/app.js添加了独立的处理函数 - 添加了
r.ProtoMajor == 2检查确保只在HTTP/2连接上推送 - 使用
http.PushOptions传递适当的请求头 - 修正了HTML字符串的引号转义问题
使用以下命令生成测试证书:
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes -subj "/C=US/ST=State/L=City/O=Org/CN=localhost"
访问https://localhost:8080并检查Chrome开发者工具的Network标签,应该能看到app.js和styles.css的Type显示为"Push"。

