Background
- enables efficient server-to-client streaming of text-based event data
- eg. real-time notifications or updates generated by the server
- two new components: EventSource interface & “event stream” data format
- EventSource interface allows the client to receive push notifications from the server as DOM events
- “event stream” data format is used to deliver the individual updates
- efficient way to handle real-time data in the browser
- low latency via a single, long-lived connection
- efficient browser message parsing with no unbounded buffer
- automatic tracking of last seen message and auto connect
- client messages as DOM events
- is essentially a efficient, cross-browser implementation of XHR streaming
- except the browser handles all the connection management and message parsing
EventSource API
- need to specify the URL of the SSE event stream, resource and resister the appropriate JS event listeners on the object
- implementation logic is handled by the browser
- connection is negotiated on our behalf, received data is parsed incrementally, message boundaries are identified, and finally a DOM event is fired by the browser
- SSE provides a memory-efficient implementation of XHR streaming
- raw XHR connection buffers the full received response until the connection is dropped
- SSE connection can discard processed messages
- if the connection is dropped, EventSource will automatically reconnect and optionally advertise the ID of the last seen message, such lost messages can be retransmitted
- on browsers that do not support EventSource API natively, we can emulate it with an optional JS library (ie. a “polyfill”) - but it will not be as efficient
- XHR polling incurs message delays and high request overhead
- XHR long-polling minimizes latency delays but has high request overhead
- XHR streaming support is limited and buffers all the data in memory
Event Stream Protocol
- an SSE event stream is delivered as a streaming HTTP response: the client initiates a regular HTTP request, the server responds with a custom “text/event-stream” content-type, then streams the UTF-8 encoded event data
- event-stream protocol is quite trivial to understand and implement
- event payload is the value of one or more adjacent data fields
- event may carry an optional ID and an event type string
- event boundaries are marked by newlines
- on the client side: parse by looking for newline separators → extract payload → check for ID & type → dispatch DOM event to notify the application
- if a type is present, then a custom DOM event is fired, and otherwise the generic “onmessage” callback is invoked
SSE Use Cases & Performance
-
low latency - messages can be pushed the moment they become available on the server
-
min message overhead - long lived-connection, event-stream protocol, gzip compression
-
auto-reconnect, message notifications as DOM events
-
SSE has two main limitations
- does not address the request streaming use cases (eg. streaming a large upload to the server)
- specifically designed to transfer UTF-8 data, binary streaming, while possible, is inefficient (base64 encoding an arbitrary binary object incurs a 33% byte overhead)
- can be resolved at the application layer - SSE delivers a notification about an available binary asset, and the application dispatches an XHR request to fetch it
- +1 RTT, but leverages the services provided by XHR - response caching, transfer-encoding (compression), etc
- streamed assets cannot be cached by the browser cache
- can be resolved at the application layer - SSE delivers a notification about an available binary asset, and the application dispatches an XHR request to fetch it
-
note that real-time push, just as polling, can negatively impact battery - consider batching messages, and eliminate unnecessary keepalives; an SSE connection is not dropped while the radio is idle
-
SSE is a simple and convenient on top of a regular HTTP connection, but existing network middleware (eg. proxy servers, firewalls), which are not SSE aware may cause problems - intermediaries may choose the buffer the event-stream data, which translates to increased latency or a broken SSE connection
- can consider delivering an SSE event-stream over a TLS connection (instead of HTTP)
- according to Chat: when traffic is encrypted with TLS, the intermediaries are unable to inspect the contents of the messages and thus more likely to fwd it as-is instead of manipulating it
- can consider delivering an SSE event-stream over a TLS connection (instead of HTTP)