diff options
Diffstat (limited to 'content/h2push.article')
-rw-r--r-- | content/h2push.article | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/content/h2push.article b/content/h2push.article new file mode 100644 index 0000000..9079f8d --- /dev/null +++ b/content/h2push.article @@ -0,0 +1,123 @@ +HTTP/2 Server Push +24 Mar 2017 +Tags: http, technical + +Jaana Burcu Dogan, Tom Bergan + +* Introduction + +HTTP/2 is designed to address many of the failings of HTTP/1.x. +Modern web pages use many resources: HTML, stylesheets, +scripts, images, and so on. In HTTP/1.x, each of these resources must +be requested explicitly. This can be a slow process. +The browser starts by fetching the HTML, then learns of more resources +incrementally as it parses and evaluates the page. Since the server +must wait for the browser to make each request, the network is often +idle and underutilized. + +To improve latency, HTTP/2 introduced _server_push_, which allows the +server to push resources to the browser before they are explicitly +requested. A server often knows many of the additional resources a +page will need and can start pushing those resources as it responds +to the initial request. This allows the server to fully utilize an +otherwise idle network and improve page load times. + +.image h2push/serverpush.svg _ 600 + +At the protocol level, HTTP/2 server push is driven by `PUSH_PROMISE` +frames. A `PUSH_PROMISE` describes a request that the server predicts the +browser will make in the near future. As soon as the browser receives +a `PUSH_PROMISE`, it knows that the server will deliver the resource. +If the browser later discovers that it needs this resource, it will +wait for the push to complete rather than sending a new request. +This reduces the time the browser spends waiting on the network. + +* Server Push in net/http + +Go 1.8 introduced support for pushing responses from an [[https://golang.org/pkg/net/http/#Server][`http.Server`]]. +This feature is available if the running server is an HTTP/2 server +and the incoming connection uses HTTP/2. In any HTTP handler, +you can assert if the http.ResponseWriter supports server push by checking +if it implements the new [[https://golang.org/pkg/net/http/#Pusher][`http.Pusher`]] interface. + +For example, if the server knows that `app.js` will be required to +render the page, the handler can initiate a push if `http.Pusher` +is available: + +.code h2push/pusher.go /START/,/END/ + +The Push call creates a synthetic request for `/app.js`, +synthesizes that request into a `PUSH_PROMISE` frame, then forwards +the synthetic request to the server's request handler, which will +generate the pushed response. The second argument to Push specifies +additional headers to include in the `PUSH_PROMISE`. For example, +if the response to `/app.js` varies on Accept-Encoding, +then the `PUSH_PROMISE` should include an Accept-Encoding value: + +.code h2push/pusher.go /START1/,/END1/ + +A fully working example is available at: + + $ go get golang.org/x/blog/content/h2push/server + + +If you run the server and load [[https://localhost:8080][https://localhost:8080]], +your browser's developer tools should show that `app.js` and +`style.css` were pushed by the server. + +.image h2push/networktimeline.png _ 605 + +* Start Your Pushes Before You Respond + +It's a good idea to call the Push method before sending any bytes +of the response. Otherwise it is possible to accidentally generate +duplicate responses. For example, suppose you write part of an HTML +response: + + + <html> + <head> + <link rel="stylesheet" href="a.css">... + + +Then you call Push("a.css", nil). The browser may parse this fragment +of HTML before it receives your PUSH_PROMISE, in which case the browser +will send a request for `a.css` in addition to receiving your +`PUSH_PROMISE`. Now the server will generate two responses for `a.css`. +Calling Push before writing the response avoids this possibility entirely. + +* When To Use Server Push + +Consider using server push any time your network link is idle. +Just finished sending the HTML for your web app? Don't waste time waiting, +start pushing the resources your client will need. Are you inlining +resources into your HTML file to reduce latency? Instead of inlining, +try pushing. Redirects are another good time to use push because there +is almost always a wasted round trip while the client follows the redirect. +There are many possible scenarios for using push -- we are only getting started. + +We would be remiss if we did not mention a few caveats. First, you can only +push resources your server is authoritative for -- this means you cannot +push resources that are hosted on third-party servers or CDNs. Second, +don't push resources unless you are confident they are actually needed +by the client, otherwise your push wastes bandwidth. A corollary is to +avoid pushing resources when it's likely that the client already has +those resources cached. Third, the naive approach of pushing all +resources on your page often makes performance worse. When in doubt, measure. + +The following links make for good supplemental reading: + +- [[https://calendar.perfplanet.com/2016/http2-push-the-details/][HTTP/2 Push: The Details]] +- [[https://www.igvita.com/2013/06/12/innovating-with-http-2.0-server-push/][Innovating with HTTP/2 Server Push]] +- [[https://github.com/h2o/h2o/issues/421][Cache-Aware Server Push in H2O]] +- [[https://developers.google.com/web/fundamentals/performance/prpl-pattern/][The PRPL Pattern]] +- [[https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0][Rules of Thumb for HTTP/2 Push]] +- [[https://tools.ietf.org/html/rfc7540#section-8.2][Server Push in the HTTP/2 spec]] + +* Conclusion + +With Go 1.8, the standard library provides out-of-the-box support for HTTP/2 +Server Push, giving you more flexibility to optimize your web applications. + +Go to our [[https://http2.golang.org/serverpush][HTTP/2 Server Push demo]] +page to see it in action. |