By the end of the lesson, you can explain how SSE works, the role of reconnection and Last-Event-ID, the limits of authentication and infrastructure, and distinguish SSE from general HTTP streaming.
Why is it needed?
Long polling requires a new HTTP exchange after every response. If the server can send many messages on the same open response, the header cost and the latency are smaller. For many status-watching interfaces it is enough for data to flow only from the server towards the client.
What is SSE?
SSE is an HTTP-based text event stream: the server sends several events in a single HTTP response. According to the WHATWG (Web Hypertext Application Technology Working Group) HTML (Hypertext Markup Language) Standard, the MIME (Multipurpose Internet Mail Extensions) type of the format is text/event-stream, it is UTF-8 encoded (8-bit Unicode Transformation Format), events end with a blank line, and the fields are: event (type), data (data), id (identifier of the last event), retry (reconnection time in milliseconds). A line starting with a colon is a comment that the client ignores; according to the standard some legacy proxies drop the connection after a short timeout, so the author may send such a comment roughly every 15 seconds as a keep-alive.
In the browser the EventSource API receives it. According to MDN the connection is one-way: the client cannot send events to the server, so the client's actions go on a separate channel, for example a fetch() request.
Reconnection and Last-Event-ID
By default EventSource reconnects after the connection breaks; the server can give a waiting time with the retry field. On reconnection the browser sends the identifier of the last received event in the Last-Event-ID header. According to the standard a 204 No Content response stops reconnection, and any other non-200 status or wrong Content-Type means the connection finally fails, and the client does not try again.
Automatic reconnection does not guarantee that missed events arrive. The server must retain the events (or provide some other way of recovery) to be able to continue from Last-Event-ID; if it cannot serve the old position, the client must request a fresh snapshot.
Authentication and infrastructure
According to the standard, the EventSource constructor accepts only a URL and the withCredentials option; arbitrary request headers cannot be set. With cookie-based authentication, authentication, credential handling and cross-origin rules must be aligned. Writing a long-lived sensitive token into the URL is a bad choice, because the address can end up in logs.
Buffering by an intermediate proxy can delay events (RFC 6202 also notes in general that streaming can be prevented by intermediaries that buffer the whole response). According to MDN, under HTTP/1.1 the number of open connections per browser and domain is very low (6) and shared across tabs; under HTTP/2 the number of parallel streams is negotiated, with a default of 100.
General HTTP streaming
According to RFC 6202, in HTTP streaming the server does not complete the response and sends data on it when it has some. The response body can also be read in chunks with the fetch API, in any format (for example line-delimited JSON, NDJSON, Newline-Delimited JSON). Then the application has its own parser and itself designs the message boundary, the reconnection and the resume. Because intermediate components may alter the chunking, the message boundary must be marked at the application level, not relying on HTTP chunking. An incoming chunk of bytes is not necessarily a complete message, so the parser must keep a remainder buffer and limit its size.
Characteristics
Aspect
SSE / HTTP streaming
Direction
One-way: server → client
Initiator
The client opens the connection; the server sends the events
Connection persistence
A persistently open HTTP response
Latency
Low: the event can go at once
Load
An open connection per client; no repeated header cost
Fault tolerance
Automatic reconnection; retention or a snapshot is needed for missed events
When it fits
Status monitoring, notification feed, live interface for data coming only from the server
When it does not
Dense two-way exchange; authentication with special headers; binary data (SSE is text)
Common misconceptions
Statement
Clarification
"SSE is two-way."
Server → client; the client sends in a separate request.
"Automatic reconnection is lossless."
Without retention on the server, a gap may occur.
"Any header can be set for SSE."
The constructor accepts no headers.
"SSE is always more real-time than polling."
Lower latency, but a proxy may buffer.
In short
SSE is a one-way HTTP event stream (text/event-stream), received by EventSource.
id and Last-Event-ID allow resuming if the server retains the events.
There is no custom request header; infrastructure (proxy, connection count) constrains it.
In general HTTP streaming the application solves framing and resuming.
Review questions
What must the server provide to use Last-Event-ID?
Why can SSE be delayed behind a proxy?
What must be solved separately with an NDJSON stream based on fetch?
Server-Sent Events and HTTP Streaming
Objectives
By the end of the lesson, you can explain how SSE works, the role of reconnection and
Last-Event-ID, the limits of authentication and infrastructure, and distinguish SSE from general HTTP streaming.Why is it needed?
Long polling requires a new HTTP exchange after every response. If the server can send many messages on the same open response, the header cost and the latency are smaller. For many status-watching interfaces it is enough for data to flow only from the server towards the client.
What is SSE?
SSE is an HTTP-based text event stream: the server sends several events in a single HTTP response. According to the WHATWG (Web Hypertext Application Technology Working Group) HTML (Hypertext Markup Language) Standard, the MIME (Multipurpose Internet Mail Extensions) type of the format is
text/event-stream, it is UTF-8 encoded (8-bit Unicode Transformation Format), events end with a blank line, and the fields are:event(type),data(data),id(identifier of the last event),retry(reconnection time in milliseconds). A line starting with a colon is a comment that the client ignores; according to the standard some legacy proxies drop the connection after a short timeout, so the author may send such a comment roughly every 15 seconds as a keep-alive.In the browser the
EventSourceAPI receives it. According to MDN the connection is one-way: the client cannot send events to the server, so the client's actions go on a separate channel, for example afetch()request.Reconnection and
Last-Event-IDBy default
EventSourcereconnects after the connection breaks; the server can give a waiting time with theretryfield. On reconnection the browser sends the identifier of the last received event in theLast-Event-IDheader. According to the standard a204 No Contentresponse stops reconnection, and any other non-200 status or wrongContent-Typemeans the connection finally fails, and the client does not try again.Automatic reconnection does not guarantee that missed events arrive. The server must retain the events (or provide some other way of recovery) to be able to continue from
Last-Event-ID; if it cannot serve the old position, the client must request a fresh snapshot.Authentication and infrastructure
According to the standard, the
EventSourceconstructor accepts only a URL and thewithCredentialsoption; arbitrary request headers cannot be set. With cookie-based authentication, authentication, credential handling and cross-origin rules must be aligned. Writing a long-lived sensitive token into the URL is a bad choice, because the address can end up in logs.Buffering by an intermediate proxy can delay events (RFC 6202 also notes in general that streaming can be prevented by intermediaries that buffer the whole response). According to MDN, under HTTP/1.1 the number of open connections per browser and domain is very low (6) and shared across tabs; under HTTP/2 the number of parallel streams is negotiated, with a default of 100.
General HTTP streaming
According to RFC 6202, in HTTP streaming the server does not complete the response and sends data on it when it has some. The response body can also be read in chunks with the
fetchAPI, in any format (for example line-delimited JSON, NDJSON, Newline-Delimited JSON). Then the application has its own parser and itself designs the message boundary, the reconnection and the resume. Because intermediate components may alter the chunking, the message boundary must be marked at the application level, not relying on HTTP chunking. An incoming chunk of bytes is not necessarily a complete message, so the parser must keep a remainder buffer and limit its size.Characteristics
Common misconceptions
In short
text/event-stream), received byEventSource.idandLast-Event-IDallow resuming if the server retains the events.Review questions
Last-Event-ID?fetch?Learning resources
EventSource, reconnection.