82 lines
4.1 KiB
Markdown
82 lines
4.1 KiB
Markdown
# 1. Two protocols, one question
|
|
|
|
Next: [2. The SSE lifecycle](02-sse-lifecycle.md)
|
|
|
|
---
|
|
|
|
Server-Sent Events and WebSocket get compared as if they were rivals for the same job. They are
|
|
not. The question that separates them is much smaller than "which is better", and it is this:
|
|
|
|
> **Does the client need to send anything after the first request?**
|
|
|
|
If the answer is no — a dashboard, a progress bar, a notification feed, a log tail, a
|
|
"your export is ready" ping — SSE is the whole answer, and it is a return type rather than a
|
|
subsystem. If the answer is yes, and the messages are frequent or need routing between clients,
|
|
you want WebSocket, and almost certainly STOMP on top of it.
|
|
|
|
Everything else in the comparison follows from that one asymmetry.
|
|
|
|
## What each one costs you to set up
|
|
|
|
| | SSE | STOMP over WebSocket |
|
|
|---|---|---|
|
|
| Dependency | `spring-boot-starter-webmvc` | `spring-boot-starter-websocket` |
|
|
| Auto-configuration involved | none | `spring-boot-websocket` |
|
|
| Server-side surface | a handler method returning `SseEmitter` | `@EnableWebSocketMessageBroker`, a configurer, a broker, a converter stack |
|
|
| Transport | one long-lived HTTP response | an HTTP/1.1 Upgrade to a framed, bidirectional connection |
|
|
| Client | `new EventSource(url)`, built into every browser | a STOMP library |
|
|
| Reconnect | automatic, with `Last-Event-ID` | yours to write |
|
|
| Server knows who is connected | no | yes — `SimpUserRegistry`, connect/subscribe/disconnect events |
|
|
| Payload | UTF-8 text only | text or binary |
|
|
|
|
The dependency line is the Boot 4 detail worth stating out loud. `spring-boot-starter-websocket`
|
|
pulls in `spring-boot-websocket`, which is where the auto-configuration lives. Depending on
|
|
`org.springframework:spring-websocket` and `spring-messaging` directly compiles and starts, and
|
|
then nothing works — the same rule that catches people with `spring-kafka` in
|
|
[`../kafka-basics`](../kafka-basics/README.md) and `spring-rabbit` in
|
|
[`../rabbitmq`](../rabbitmq/README.md). In Boot 4, **depending on a library rather than on its
|
|
Boot starter means you are missing its auto-configuration.**
|
|
|
|
## What SSE is not
|
|
|
|
Two things people assume, both wrong, both measured in this module:
|
|
|
|
**"It pins a thread per client."** It does not. `SseEmitter` switches the request to asynchronous
|
|
mode; the request thread goes back to the pool immediately and the response stays open with
|
|
nothing attached to it. [`SseConcurrencyTest`](../src/test/java/com/ankurm/ssews/SseConcurrencyTest.java)
|
|
holds forty streams open against a connector whose pool is capped at ten:
|
|
|
|
```
|
|
emitters open : 40
|
|
connector pool size : 10 (max 10)
|
|
connector active : 0
|
|
```
|
|
|
|
**"You have to pass a media type or it calls `toString()`."** Also not true, and the opposite is
|
|
closer to it. See [3. The payload](03-the-payload.md).
|
|
|
|
## What SSE genuinely cannot do
|
|
|
|
- **Take input.** `EventSource` issues one GET and never sends again. Client-to-server traffic has
|
|
to go over ordinary HTTP requests, which is fine for low rates and awful for a chat.
|
|
- **Send custom headers.** The browser's `EventSource` has no header API, so bearer-token
|
|
authentication needs a cookie or a query parameter. `withCredentials` exists; `Authorization`
|
|
does not.
|
|
- **Carry binary.** The format is line-oriented UTF-8. Binary means base64, which costs a third.
|
|
- **Tell you a client left.** There is no disconnect event, only a write that fails later —
|
|
see [2. The SSE lifecycle](02-sse-lifecycle.md).
|
|
- **Escape the browser's per-origin connection limit.** Over HTTP/1.1 a browser allows about six
|
|
concurrent connections to one origin, and an open SSE stream is one of them, *per tab*. Four
|
|
tabs of a dashboard is 4 streams; six is a hung site. HTTP/2 multiplexes and the limit
|
|
effectively disappears, which makes "do we serve this over HTTP/2?" a real part of the decision.
|
|
|
|
## What STOMP costs
|
|
|
|
A broker, a message-converter stack, a session registry, an origin policy, and a set of routing
|
|
rules whose defaults are not what you would guess. Chapters
|
|
[4](04-stomp.md) and [5](05-limits.md) are that list.
|
|
|
|
---
|
|
|
|
Next: [2. The SSE lifecycle](02-sse-lifecycle.md)
|