I don't know why people keep trying desperately to avoid the simplicity and flexibility of WebSockets.
A lot of times, what people need is a bidirectional connection yet somehow they convince themselves that SSE is better for the job... But they end up with two different types of streams; HTTP for writes and responses and SSE for passively consuming real-time data... Two different stream types with different lifecycles; one connection could fail while the other is fine... There is no way to correctly identify what is the current connection status of the app because there are multiple connections/statuses and data comes from multiple streams... Figuring out how to merge data coming from HTTP responses with data coming in passively from the SSE is messy and you have no control over the order in which the events are triggered across two different connections...
You can't enforce a serial, sequential, ordered flow of data over multiple connections as easily, it gets messy.
With WebSockets, you can easily assign an ID to requests and match it with a response. There are plenty of WebSocket frameworks which allow you to process messages in-order. The reason they work and are simple is because all messages pass over a single connection with a single state. Recovering from lost connections is much more straight forward.
who's to say your data is coming from multiple streams? You can propagate any updates you need to make in the application to a single stream (like SSE or a long-lived response) in place of a WebSocket. your http responses can just be always 204 if all they're doing is handling updates and pushing events to aforementioned single stream.
It should say "When used over HTTP/1" instead of "When not used over HTTP/2" because nowadays we also have HTTP/3, and browsers barely even use HTTP/1, so I would say it's pretty safe to ignore that warning.
> Unless you mean on HTTP2?
Any version of HTTP that supports multiplexing.
> But aren't WS connections also multiplexed over HTTP2 in that case?
There is RFC 8441 but I don't think it's actually implemented in the browsers.
I've noticed some weird behaviors with the EventSource impl that browsers ship with. Chief among them being the default behavior is to infinitely reconnect after the server closes the stream, so you have to coordinate some kind of special stop event to stop the client from reconnecting. You wouldn't have that problem with the stream object from Response.body
The SSE protocol is actually just a long-running stream like I mentioned but with specific formatting for each chunk (id, event, and data fields)
as a side note, eventkit actually exports utilities to support SSE both on client and server. The reason you'd want to use eventkit in either case is because it ships with some extra transformation and observability goodies. https://hntrl.github.io/eventkit/guide/examples/http-streami...
The reconnect thing is actually quite helpful for mobile use cases. Say the user switches the tab, closes their browser or loses network and then they return. Since SSE is stateless from the client's perspective, the client can just reconnect and continue receiving messages. Whereas with WS there's handshakes to worry about--and also other annoyances like what to do with pending requests before connection was lose.
SSE is great. Most things with websockets would be fine with SSE.
Also I don't see it being much easier here than a few primitives and learning about generator functions if you haven't had experience with them. I appreciate the helper, but the API is pretty reasonable as-is IMO
I’m experimenting with SSE for realtime project deployment logs in https://lunni.dev/ and it’s been extremely pleasant so far.
The only problem is, if you want to customize the request (e.g. send a POST or add a header),you have to use a third-party implementation (e.g. one from Microsoft [1]), but I hope this can be fixed in the standards later.
The helper example was a sore attempt to plug the project I've been working on (tinkering with it is how I came up with the example). The library I plugged has much more to do with enabling a more flexible reactive programming model in js, but just so happens to plug into the stream API pretty handily. Still an interesting look IMO if you're into that kind of stuff
No worries, I know how it feels! (I said, plugging away my own project in a sibling comment, lol)
I do like the reactive approach (in fact, I’ve reinvented something similar over SSE). I feel a standards-based solution is just ever so slightly more robust/universal.
SSE doesn't support binary data without encoding to something base64 first. These days I'd recommend a fetch stream with TLV messages first, followed by WebSocket.
Cloudflare doesn't officially support SSE, but if you send keepalives events every 15 or 20sec or so you can reliably use SSE for 40 min + in my experiance.
No server traffic for 100+ sec officially results in a 524, so you could possibly make that keepalive interval longer, but I haven't tested it.
Make sure to have the new style cache rule with Bypass cache selected and absolutely make sure you are using HTTP/2 all the way to the origin.
The 6 connections per browser limit of HTTP/1.1 SSE was painful, and I am pretty sure auto negotiation breaks, often in unexpected ways with a HTTP/1.1 origin.
On top of the comments below about SSE, I'd also point out that Cloudflare is doing some interesting stuff around serverless resumable websockets. They also have stuff for WebRTC.
A lot of times, what people need is a bidirectional connection yet somehow they convince themselves that SSE is better for the job... But they end up with two different types of streams; HTTP for writes and responses and SSE for passively consuming real-time data... Two different stream types with different lifecycles; one connection could fail while the other is fine... There is no way to correctly identify what is the current connection status of the app because there are multiple connections/statuses and data comes from multiple streams... Figuring out how to merge data coming from HTTP responses with data coming in passively from the SSE is messy and you have no control over the order in which the events are triggered across two different connections...
You can't enforce a serial, sequential, ordered flow of data over multiple connections as easily, it gets messy.
With WebSockets, you can easily assign an ID to requests and match it with a response. There are plenty of WebSocket frameworks which allow you to process messages in-order. The reason they work and are simple is because all messages pass over a single connection with a single state. Recovering from lost connections is much more straight forward.