How to Make My Web Server written in Golang to support HTTP/2 Server Push?
Asked Answered
R

2

9

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 ?

Roshan answered 5/1, 2017 at 16:48 Comment(3)
Not much info, but on topic: #37873424Bunsen
note that "Push notifications" is not the same as "server push". By the way my experience on Go running in Google AppEngine is I need to set http headers like the following to indicate what files to push: link:</images/bg.jpg>; rel=preload; as=image,</analytics.js>; rel=preload; as=scriptEthiopian
rakyll.org/http2pushPuberty
O
9

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.

Olia answered 5/1, 2017 at 17:36 Comment(1)
Go 1.8 is also due out in Feb.Manor
P
4

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.

Pustulate answered 13/2, 2018 at 20:23 Comment(1)
The link to your article is currently broken. Is there an updated link?Cotter

© 2022 - 2024 — McMap. All rights reserved.