HTTP/2 Server Push vs Websockets vs Server-Sent Events

One of the key features of HTTP/2 is server push, a way of sending resources over HTTP before the browser requests them. It’s related to the older API of SSE (server-sent events), which can be done, with more overhead, over HTTP/1.1, but server push is done in a more stream-oriented way. This post will focus on the differences between the two, as well as what prevents it from being used like websockets.

Server push is typically presented as an alternative to inlining page resources like CSS [1], limited in scope to when a web page is first loaded.

This is because the HTTP/2 push protocol is built to be browser-controlled. Specifically, an HTTP/2 PUSH-enabled server will send a response that contains a PUSH_PROMISE frame for every resource that it expects will be requested, containing the headers that would be included with that request. These are collected by the browser in a store for PUSH_PROMISE frames. The browser can then check its PUSH_PROMISE store before making any requests; if it finds the headers for that request there, it can simply wait for the resource to arrive. [2]

Client ---->
GET example.com/index.html
<---- Server
PUSH_PROMISE:
GET example.com/index.html
<---- Server
200 OK
/Headers/
`link: script.js`
/Body/
<!DOCTYPE html>
<html><head><title></title><script src="script.js"></script></head><body><p></body>
</html>
Client:
[find script.js in store; don't make request]
<---- Server
`200 OK`
/Body/
`console.log('hello world);`

But it’s not immediately clear what happens when a server pushes resources that haven’t been requested. Is it possible to use a persistent HTTP connection to send resources as you would through a websocket channel? The benefits of this approach might include a security advantage [3], and it might help simplify web app architectures: for instance, we you need both the structure of a REST API and the push capability of websockets. This feature would have to be implemented by browsers, but I don’t see any reason that can’t, in principle, be done.

Other Notes:

-

  • Server-sent events have a more websockets-like API, mimicking the familiar Javascript event API.
  • Another push option is the Push API, distinct from HTTP push. It’s a distinct protocol: https://w3c.github.io/push-api/

[1] https://blog.golang.org/h2push [2] https://en.wikipedia.org/wiki/HTTP/2_Server_Push#How_HTTP/2_PUSH_works_at_a_protocol_level [3] https://stackoverflow.com/questions/28582935/does-http-2-make-websockets-obsolete