Server-Sent Events (SSE) client
Starting with HttpClient 5.6 there is an optional Server-Sent Events (SSE)
module, httpclient5-sse, for consuming long-lived event streams over HTTP/1.1
and HTTP/2 using the async transport.
Unlike WebSockets, SSE is strictly one-way (server → client) and reuses plain
HTTP with the media type text/event-stream. The SSE client in HttpClient
focuses on:
- correct parsing of the SSE wire format (fields
data:,event:,id:,retry:and comments), - robust reconnection with backoff strategies and
Last-Event-IDpropagation, and - a simple listener API for application code.
Module and dependency
SSE support lives in a separate module:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5-sse</artifactId>
<version>${httpclient5.version}</version>
</dependency>
This module depends on the async client (httpclient5) and reuses the existing
I/O reactor, connection pooling and TLS strategies.
Core types
All SSE APIs are in the package org.apache.hc.client5.http.sse.
-
EventSourceRepresents a single SSE connection (the client-side equivalent of a browser
EventSourceobject). It exposes:start()/cancel()– idempotent lifecycle methods,lastEventId()/setLastEventId(String)– tracking and sendingLast-Event-ID, and- simple header management (
setHeader,removeHeader,getHeaders).
Implementations are provided by this module; you normally obtain an
EventSourcevia a factory such asSseExecutor. -
EventSourceListenerCallback interface that receives parsed SSE events and lifecycle signals: open, event, comment, retry hints, errors and closed. The listener is wired when the
EventSourceis created and must be fast / non-blocking. -
BackoffStrategyandBackoffStrategiesStrategy interface controlling reconnect delays after disconnects:
long nextDelayMs(int attempt, long previousDelayMs, Long serverRetryHintMs); default boolean shouldReconnect(int attempt, long previousDelayMs, Long serverRetryHintMs) { return true; }Implementations in
BackoffStrategiescover common policies such as constant, exponential and jittered backoff. The strategy can honour server hints fromretry:fields or HTTPRetry-Afterheaders, or ignore them. -
SseExecutorHigh-level entry point that ties an async
CloseableHttpAsyncClientto one or more SSE streams. It is responsible for:- opening the initial SSE request,
- driving reconnects according to a
BackoffStrategy, - feeding parsed events to the
EventSourceListener, and - updating
Last-Event-IDas events are received.
See the Javadoc for exact factory methods and configuration options.
Basic usage – subscribing to an SSE stream
A typical flow is:
- Create or reuse a
CloseableHttpAsyncClient. - Build an
SseExecutorbound to that client. - Implement an
EventSourceListenerthat handles events. - Open an
EventSourcefor the SSE endpoint and callstart().
Simplified sketch:
// 1) Async client
final CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
client.start();
// 2) Listener that processes incoming events
final EventSourceListener listener = new EventSourceListener() {
@Override
public void onEvent(final SseEvent event) {
System.out.println("event: " + event.getEventName());
System.out.println("id : " + event.getId());
System.out.println("data : " + event.getData());
}
@Override
public void onError(final Throwable cause) {
cause.printStackTrace(System.err);
}
@Override
public void onClosed() {
System.out.println("SSE stream closed");
}
// see Javadoc for the full callback set (open, comment, retry hint, etc.).
};
// 3) Backoff policy (e.g. bounded exponential with jitter)
BackoffStrategy backoff = BackoffStrategies.exponentialJitter(...);
// 4) Create an EventSource via SseExecutor (see actual factory signature in code)
final SseExecutor sse = ...
final EventSource source = sse.open(
URI.create("https://example.com/events"),
listener,
backoff);
// 5) Start streaming
source.start();
The exact factory methods and builder options for
SseExecutormay evolve; always refer to the Javadoc oforg.apache.hc.client5.http.sse.SseExecutorfor up-to-date signatures. The examples below show complete, compilable programs.
Last-Event-ID and resume
The SSE client tracks the last non-null event id it observes:
- Incoming
id:fields update the current Last-Event-ID. - On reconnect, the
EventSourcecan send this value as theLast-Event-IDrequest header so the server can resume the stream.
You can also seed or clear this value manually:
// Seed from a persisted offset
source.setLastEventId("42");
// Inspect the current offset
final String last = source.lastEventId();
Backoff and reconnect behaviour
Reconnect logic is fully driven by the configured BackoffStrategy:
nextDelayMs(...)computes the delay before the next attempt.shouldReconnect(...)can opt out completely (for example, a strategy that never reconnects, or stops after N attempts).
The strategy receives:
-
the attempt count (1-based),
-
the previously used delay, and
-
an optional server hint (
Long serverRetryHintMs) derived from:- SSE
retry:fields, or - HTTP
Retry-Afterwhen the server returns a non-2xx response.
- SSE
This lets applications balance aggression vs. politeness and apply custom policies (for example, backoff only on certain status codes, or cap the maximum delay regardless of server hints).
Examples
Concrete examples live in the httpclient5-sse module under
org.apache.hc.client5.http.sse.example:
-
Interactive SSE client demo that connects to an SSE endpoint, logs events, and shows how to wire
SseExecutor,EventSource,EventSourceListenerand aBackoffStrategytogether. -
Synthetic load / throughput client for SSE streams. Useful as a reference when benchmarking different backoff policies or server implementations.
-
Minimal HTTP server that emits SSE events at a configurable rate, intended to be used together with
SsePerfClientfor end-to-end testing. -
HTTP/2 SSE demo. Forces H2 (TLS + ALPN), probes the negotiated protocol, and demonstrates multiplexing multiple SSE subscriptions over a single HTTP/2 connection.
Further reading
-
SSE wire format and semantics are defined in the HTML Living Standard (“Server-sent events” section).
-
For the full API, see the Javadoc of:
org.apache.hc.client5.http.sse.EventSourceorg.apache.hc.client5.http.sse.EventSourceListenerorg.apache.hc.client5.http.sse.BackoffStrategyorg.apache.hc.client5.http.sse.BackoffStrategiesorg.apache.hc.client5.http.sse.SseExecutor




