My Web Server is Coded in Golang and supports HTTPS. I wish to leverage HTTP/2 Server Push features in the Web Server. The following Link explains how to convert HTTP Server to Support HTTP/2 :-
https://www.ianlewis.org/en/http2-and-go
However, it is not clear how to implement the Server Push notifications in Golang.
- How should I add the Server Push functionality ?
- How do I control, or manage, the documents and files to be Pushed ?
Go's standard library HTTP server supports HTTP/2 by default.
Once you've set up your handlers, call the http. ListenAndServe function to start the server and listen for requests. In this first chunk of code, you set up the package for your Go program, import the required packages for your program, and create two functions: the getRoot function and the getHello function.
Go 1.7 and older do not support HTTP/2 server push in the standard library. Support for server push will be added in the upcoming 1.8 release (see the release notes, expected release is February).
With Go 1.8 you can use the new http.Pusher interface, which is implemented by net/http's default ResponseWriter. Pushers Push method returns ErrNotSupported, if server push is not supported (HTTP/1) or not allowed (the client has disabled server push).
Example:
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)
}
If you want to use server push with Go 1.7 or older use can use the golang.org/x/net/http2 and write the frames directly.
As mentioned in other answers, you can make use of Go 1.8 feature (cast the writer to http.Pusher
and then use the Push
method).
That comes with a caveat: you must be serving the HTTP2 traffic right from your server.
If you're behind a proxy like NGINX, this might not work. If you want to consider that scenario, you can make use of the Link
header to advertise the URLs to be pushed.
// 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.: I wrote more about this here https://ops.tips/blog/nginx-http2-server-push/ if you're interested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With