如何让我用 Golang 编写的 Web 服务器支持 HTTP/2 服务器推送?
How to Make My Web Server written in Golang to support HTTP/2 Server Push?
我的 Web 服务器是用 Golang 编写的,并且支持 HTTPS。我希望利用 Web 服务器中的 HTTP/2 服务器推送功能。以下 Link 说明如何将 HTTP 服务器转换为支持 HTTP/2 :-
https://www.ianlewis.org/en/http2-and-go
但是,目前还不清楚如何在Golang中实现服务器推送通知。
- 我应该如何添加服务器推送功能?
- 如何控制或管理要推送的文档和文件?
Go 1.7 及更早版本不支持 HTTP/2 标准库中的服务器推送。即将发布的 1.8 版本中将添加对服务器推送的支持(参见 release notes,预计发布时间为 2 月)。
在 Go 1.8 中,您可以使用新的 http.Pusher 接口,该接口由 net/http 的默认 ResponseWriter 实现。 Pushers 推送方法 returns ErrNotSupported,如果不支持服务器推送 (HTTP/1) 或不允许(客户端已禁用服务器推送)。
示例:
package main
import (
"io"
"log"
"net/http"
)
func main() {
http.HandleFunc("/pushed", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello server push")
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if pusher, ok := w.(http.Pusher); ok {
if err := pusher.Push("/pushed", nil); err != nil {
log.Println("push failed")
}
}
io.WriteString(w, "hello world")
})
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
}
如果你想在 Go 1.7 或更早版本中使用服务器推送,可以使用 golang.org/x/net/http2 并直接写入框架。
如其他答案中所述,您可以使用 Go 1.8 功能(将编写器转换为 http.Pusher
,然后使用 Push
方法)。
附带一个警告:您必须直接从您的服务器提供 HTTP2 流量。
如果您使用像 NGINX 这样的代理,这可能行不通。如果你想考虑那种情况,你可以利用 Link
header 来宣传要推送的 URL。
// In the case of HTTP1.1 we make use of the `Link` header
// to indicate that the client (in our case, NGINX) should
// retrieve a certain URL.
//
// See more at https://www.w3.org/TR/preload/#server-push-http-2.
func handleIndex(w http.ResponseWriter, r *http.Request) {
var err error
if *http2 {
pusher, ok := w.(http.Pusher)
if ok {
must(pusher.Push("/image.svg", nil))
}
} else {
// This ends up taking the effect of a server push
// when interacting directly with NGINX.
w.Header().Add("Link",
"</image.svg>; rel=preload; as=image")
}
w.Header().Add("Content-Type", "text/html")
_, err = w.Write(assets.Index)
must(err)
}
ps.: 如果你有兴趣,我在这里写了更多关于这个的文章 https://ops.tips/blog/nginx-http2-server-push/。
我的 Web 服务器是用 Golang 编写的,并且支持 HTTPS。我希望利用 Web 服务器中的 HTTP/2 服务器推送功能。以下 Link 说明如何将 HTTP 服务器转换为支持 HTTP/2 :-
https://www.ianlewis.org/en/http2-and-go
但是,目前还不清楚如何在Golang中实现服务器推送通知。
- 我应该如何添加服务器推送功能?
- 如何控制或管理要推送的文档和文件?
Go 1.7 及更早版本不支持 HTTP/2 标准库中的服务器推送。即将发布的 1.8 版本中将添加对服务器推送的支持(参见 release notes,预计发布时间为 2 月)。
在 Go 1.8 中,您可以使用新的 http.Pusher 接口,该接口由 net/http 的默认 ResponseWriter 实现。 Pushers 推送方法 returns ErrNotSupported,如果不支持服务器推送 (HTTP/1) 或不允许(客户端已禁用服务器推送)。
示例:
package main
import (
"io"
"log"
"net/http"
)
func main() {
http.HandleFunc("/pushed", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello server push")
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if pusher, ok := w.(http.Pusher); ok {
if err := pusher.Push("/pushed", nil); err != nil {
log.Println("push failed")
}
}
io.WriteString(w, "hello world")
})
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
}
如果你想在 Go 1.7 或更早版本中使用服务器推送,可以使用 golang.org/x/net/http2 并直接写入框架。
如其他答案中所述,您可以使用 Go 1.8 功能(将编写器转换为 http.Pusher
,然后使用 Push
方法)。
附带一个警告:您必须直接从您的服务器提供 HTTP2 流量。
如果您使用像 NGINX 这样的代理,这可能行不通。如果你想考虑那种情况,你可以利用 Link
header 来宣传要推送的 URL。
// In the case of HTTP1.1 we make use of the `Link` header
// to indicate that the client (in our case, NGINX) should
// retrieve a certain URL.
//
// See more at https://www.w3.org/TR/preload/#server-push-http-2.
func handleIndex(w http.ResponseWriter, r *http.Request) {
var err error
if *http2 {
pusher, ok := w.(http.Pusher)
if ok {
must(pusher.Push("/image.svg", nil))
}
} else {
// This ends up taking the effect of a server push
// when interacting directly with NGINX.
w.Header().Add("Link",
"</image.svg>; rel=preload; as=image")
}
w.Header().Add("Content-Type", "text/html")
_, err = w.Write(assets.Index)
must(err)
}
ps.: 如果你有兴趣,我在这里写了更多关于这个的文章 https://ops.tips/blog/nginx-http2-server-push/。