[HN Gopher] Server Sent Events
___________________________________________________________________
Server Sent Events
Author : corentin88
Score : 54 points
Date : 2023-05-15 19:12 UTC (3 hours ago)
(HTM) web link (developer.mozilla.org)
(TXT) w3m dump (developer.mozilla.org)
| 0xCAP wrote:
| Curious why is this trending? Btw sse are pretty great, only
| thing I don't get is why they don't allow for binary payloads.
| That'd have been the icing on the cake.
| mikek wrote:
| OpenAI uses this in their APIs to stream tokens
| asplake wrote:
| Probably as a result of
| https://news.ycombinator.com/item?id=35937554
| marpstar wrote:
| My first thought was ChatGPT API's `stream` option:
| https://platform.openai.com/docs/api-
| reference/completions/c...
| b33j0r wrote:
| This got into the zeitgeist somehow. I just implemented my
| first SSE app with FastAPI last week, then I saw a youtube
| video and this post!
|
| I was implementing something with websockets and asked chatgpt
| to tell me about modern alternatives. In my years of full-
| stack... I hadn't heard of SSE, or at least never got why I
| should care.
|
| Damn, I see the limitations of REST, but I was building state
| machines and custom protocols with websockets. It's nice to
| prototype in REST again.
|
| REST+SSE ftw, I guess!
| VWWHFSfQ wrote:
| > only thing I don't get is why they don't allow for binary
| payloads
|
| I've always appreciated that it's just a simple line-oriented
| UTF-8 text protocol. Binary transfers are handled more
| efficiently with something else. Or just base64 the payload if
| it's not that big of a deal.
| mr-wendel wrote:
| My favorite use of this that I've spotted in the wild is
| https://nightride.fm (not affiliated, just a fan!). It's a
| Synthwave music site + community.
|
| In particular, I noticed that EventSource goodies are used to
| broadcast currently playing songs on each station, as well as to
| provide anon read access to their IRC server via a simple vanilla
| javascript webapp.
|
| WAY cleaner and easier than web sockets for this use case, and
| CDN friendly to boot!
| [deleted]
| rektide wrote:
| I wish there were a way to push not just anonymous data/events
| but http _resources,_ to similar effect.
|
| SSE & websockets & http streams can send anonymous data, but I'd
| like to be able to send an actual thing. As per the most core
| architecture of the web:
|
| > _Axiom 0a: Universality 2. Any resource of significance should
| be given a URI._ https://www.w3.org/DesignIssues/Axioms.html#uri
|
| Or alternatively,
|
| > _Cool URLs don 't change_ (implicitly, cool things have URLs,
| see above). https://www.w3.org/Provider/Style/URI
|
| Instead of pushing to a chat app an anonymous blob of json for a
| chat message to a room, the server could assert a
| /room/42/msg/c0f3 resource, could identify universally what it is
| it's sending. The advantage would be so high. It'd become a
| standard way to assert a resource, to make known a fact, that
| would be viable across systems. Further http requests to the
| resource would just work. Folks could link to the resource. How
| cool it would be if we could _send not just data but resources?_
|
| We have come glancingly close to getting such a thing so many
| times. The HyBi mailing list that begat websockets had a number
| of alternate more resourceful ideas floating around such as a
| BEEP protocol that allowed patterns beyond request/response of
| resources. The browser actually implements an internal protocol
| that uses HTTP2/push to send resourceful messages, web push
| protocol/RFC8030, https://datatracker.ietf.org/doc/html/rfc8030.
|
| But the underlying http2/push was de-implemented for webserving
| in general, and even when it was available, it lacked the oft
| requested ability to get notice of new pushed resources.
| (https://github.com/whatwg/fetch/issues/65 was an old request.
| https://github.com/whatwg/fetch/issues/607 had some steam in
| making it happen.) Tragic backwards moves in my view, and never
| acknowledged by blink-dev when protests arose.
|
| The best we have today is to stream json-ls events, which have an
| _@id_ property identifying them. But developers would have to
| snoop these events, and store them in a service worker, to make
| them actually accessible as http resources.
|
| I continue to hold hope eventually we'll get better at using urls
| to send data, to assert new things happening... But it's been
| nearly 30 years of me hoping, and with some fleeting exceptions
| the browser teams have seemed disinterested in making urls cool,
| in spite of a number of requests. We've been left at un-web side-
| channels like SSE & Websockets for a long long time now. Wouldn't
| it be nice to see some real growth for http capabilities that we
| really can use, that are more than abstract underlying transport
| tweaks like h2 and h3?
| quechimba wrote:
| SSE is pretty good but I have never been able to see the messages
| in firefox devtools, and doesn't work with binary data.
|
| HTTP/2 streams are just as easy to implement, and work both ways
| and support binary data.
| toomim wrote:
| ChatGPT uses SSE to stream the AI's responses, token-by-token!
| paxys wrote:
| I was looking through the implementation of chat.openai.com
| recently and was pleasantly surprised to see that it was 100%
| Server Sent Events, no Websockets.
|
| SSE is a great tool to have in your belt. I'd say it can replace
| the majority of use cases for Websockets out there today
| (basically pushing small amounts of text/JSON data to the client)
| with a tiny fraction of the complexity. Opening and maintaining a
| bidirectional TCP stream is otherwise a huge pain in the ass.
| kreetx wrote:
| Server Sent Events infamously have low global connection limit
| per origin[1], so if you have multiple tabs open for a single
| site you'll run into it pretty quickly. If it weren't for that,
| they would be great.
|
| [1] https://stackoverflow.com/questions/18584525/server-sent-
| eve...
| VWWHFSfQ wrote:
| Sophisticated services that offer SSE will have many different
| endpoint domains to get around browser limits on simultaneous
| connections to the same service.
|
| endpoint-00.example.com endpoint-01.example.com
| endpoint-02.example.com
|
| etc. It isn't specific to SSE. It's any HTTP request. SSE is
| just the most obvious because the connections stay open for
| long periods.
| paulddraper wrote:
| And that's an easy workaround, with wildcard DNS entries and
| certs.
| flaviut wrote:
| I've never worked with Web Workers, but the doc page mentions
| them at the very top. Isn't that the intended workaround? Have
| a background thread that receives the events & coordinates,
| rather than having each page deal with them?
| silverwind wrote:
| Yes, that's `ShardedWorker`.
| nikeee wrote:
| I wanted so use these in a project recently, only to find
| out that they aren't supported on Chrome for Android. This
| makes them non-usable for me, since there is no drop-in
| polyfill available yet.
| silverwind wrote:
| If you are doing websocket in there, you could fall back
| to main thread, but it comes at the cost of code
| duplication.
| toomim wrote:
| This problem is fixed by using HTTP/2.
| silverwind wrote:
| No, the browser's HTTP connection limits still apply on
| HTTP2, each `EventSource` per tab counts against this limit
| of I think 6 (?) connections.
|
| Websockets to my knowledge have no such limit because they
| are not HTTP requests.
| makkesk8 wrote:
| This is simply not true, it's negotiated between the client
| and server and defaults to 100 usually. 6 is the limit for
| http 1.1 not http/2.
|
| Source: https://developer.mozilla.org/en-
| US/docs/Web/API/Server-sent...
| nitwit005 wrote:
| I believe you have it essentially backward. Websockets
| consume a connection no matter what, as the protocol does
| not work with HTTP2 (there was an attempt, but I believe it
| wasn't adopted and abandoned).
|
| The SSE requests do work with HTTP2, as do some other old
| methods like long polling. All the tabs will generally
| share one connection to that domain.
| MetalMatze wrote:
| SSE are amazing! I've used them to push updates to clients from
| multiple goroutines (Go threads) with https://lastfm.live
|
| It's quite simple to start with on the Go backend side of things
| and the frontend things aren't too complicated either.
| clessg wrote:
| For my fellow high-IQ individuals initially confused by the
| seeming lack of content in the article, it's under 'Guides':
| https://developer.mozilla.org/en-US/docs/Web/API/Server-sent...
|
| A bit easy to miss, but includes some actual code samples and a
| really nice walkthrough. Highly encouraged even if you already
| "know" SSE and want to solidify your knowledge, I like how it
| doesn't hide any of the details.
| davidw wrote:
| How well do these work out in practice across a variety of
| platforms, behind firewalls, on phones, and so on?
| [deleted]
| lecarore wrote:
| I use this at work (Enterprise SAAS web software) and we had to
| implement a backup "polling every 5 seconds" for clients that
| would not support it. It's quite rare though. We assume that
| some caching proxy might be waiting for the GET request to be
| fully done to cache it and then give it to the user or
| something like this. The SSE would then never get updates,
| while every normal HTTP request would work
| Mogzol wrote:
| They're well supported on modern browsers, both mobile and
| desktop. If you need to support IE then you can use a polyfill.
| It's essentially just a long-running HTTP request. The main
| issue I've run into before is if your server has a response
| timeout configured then you'll need to disable or work around
| it, otherwise it will disrupt the event stream whenever the
| timeout is hit, since the event stream is just an HTTP
| response.
| pieter wrote:
| Note that this really isn't anything except the agreement to send
| messages separated by 2 new lines. The SSE object in browsers is
| old and quirky; for example, it only supports GET requests, which
| means you'll hit path length limits if you use it for something
| like LLM completion with large prompts.
|
| Luckily since there's nothing special about the browser support,
| you can very easily replace it with custom implementations.
| https://www.npmjs.com/package/@microsoft/fetch-event-source for
| example offers mostly the same API, but does offer POST requests
| and a bunch of other goodies.
| hamandcheese wrote:
| This seems like a great solution for streaming responses scoped
| to a single request. Neat!
|
| I've always used SSEs to open a more persistent comms channel
| to a browser which creates way more state and complexity both
| on the client and the server.
| jraph wrote:
| There is this agreement, and also the fact that browsers can
| forget previous messages, unlike any xhr-based custom
| implementation since the EventSource object does not provide
| methods to access previous contents. I don't know how well this
| package handles this.
|
| I agree with the note about the auto retry mechanism of
| EventSource. It does no good, is unavoidable and a big
| annoyance. The work we had to do to work around it in Tracim
| (previous job) [1] was pure madness. I see this part has not
| been touched since I left by the way.
|
| https://github.com/tracim/tracim/blob/develop/frontend_lib/s...
| patwolf wrote:
| I did a web app project with SSEs a while back. They worked well
| in the browser, but when it came time to build a mobile app
| (React Native), I had trouble finding a good library to use. I'm
| sure I could have rolled my own, but being in a time crunch I
| ended up using Firebase Cloud Messaging. Hopefully there's better
| support these days.
| no_wizard wrote:
| I know alot of websites and engineers use Websocket for _push
| only_ data. SSE is tailored made for real time one sided updates!
|
| In fact, I think it made a better chat protocol, when we built a
| chat system at a previous job, similar to Slack. We ended up
| leveraging SSE to push updates to channels and traditional HTTP
| requests to send data to the server, resulting in lower latency
| and less overhead on the server side. We did this because we
| found the following to be true:
|
| - At any given time, there are far more people reading chat
| messages than writing them
|
| - What matters is that updates after being sent to everyone else
| is that their pretty close to instantaneous but you had a 500ms
| window to allow for the server to receive a new message and then
| propagate it out. Therefore, for the sender, you update the UI
| optimistically so they aren't waiting for a response, and
| everyone else will get it in ~500ms and its imperceptible
|
| - one downside: its harder (we never figured it out before I
| left) to do indicators for when someone is typing. That really
| does seem to require two way real time connections
| stevenguh wrote:
| Slack does use websocket for "someone is typing" event:
| https://slack.engineering/real-time-messaging/
| franky47 wrote:
| One major issue I encountered with SSE is dealing with
| reconnection. WebSocket makes it very easy to detect
| differences between a loss of network connectivity, a server
| dying, and a client exiting properly (eg: closing the tab), on
| either side of the socket.
|
| Maybe there are facilities to do so with SSE that I don't know
| of, but my experience in reliable server-to-client-only comms
| with it has been a bit rough.
| VWWHFSfQ wrote:
| You pretty much just have to listen for and handle premature
| closing of the underlying TCP connection. It's the only form
| of dead peer detection you'll get if someone just abrubtly
| closes their browser tab.
| teaearlgraycold wrote:
| Do server frameworks really require you to think of the TCP
| connection?
| marcellus23 wrote:
| What was the challenge in typing indicators? My naive idea is
| that it's basically sending `typing_started` and `typing_ended`
| messages.
| yamtaddle wrote:
| You can skip the "typing ended". You're gonna need a shortish
| timeout anyway, may as well just let the "typing is
| happening" messages _all_ terminate by timeout.
| marcellus23 wrote:
| That really depends on the UX you want.
| yamtaddle wrote:
| What do you have in mind? I can't think of a case where
| you'd want "X is typing" to persist more than a second or
| _maybe_ two past the last-received message that affirmed
| X is, in fact, still typing. I can think of cases in
| which a short timeout might break down in bad ways
| (making the notice really jittery on high-latency
| connections, say) but I think those are probably just
| situations in which any "... is typing" message is
| simply gonna be bad in one way or another.
| VWWHFSfQ wrote:
| I'm guessing that since it's not a full-duplex connection you
| have to send those messages out-of-band, ie, with a separate
| POST request API
| hamandcheese wrote:
| But messages themselves are already sent out-of-band as a
| POST request, if I understand correctly. Don't see why that
| couldn't be extended to include typing indicators.
| twic wrote:
| The big problem i've run into with SSE is the connection limit
| [1]:
|
| > Warning: When not used over HTTP/2, SSE suffers from a
| limitation to the maximum number of open connections, which can
| be specially painful when opening various tabs as the limit is
| per browser and set to a very low number (6). The issue has
| been marked as "Won't fix" in Chrome and Firefox. This limit is
| per browser + domain, so that means that you can open 6 SSE
| connections across all of the tabs to www.example1.com and
| another 6 SSE connections to www.example2.com. (from
| Stackoverflow). When using HTTP/2, the maximum number of
| simultaneous HTTP streams is negotiated between the server and
| the client (defaults to 100).
|
| The natural way to use SSE is to create an EventSource on each
| page. If you do this, and your user opens six tabs, they can
| now no longer make HTTP requests to your site. Not just SSE
| requests, any HTTP requests at all!
|
| It's also quite natural, i think, to want to use multiple
| separate streams. It's very convenient to write separate
| endpoints for various kinds of data that a page might want, for
| example one for streaming numerical data, one for control
| messages, and one for descriptive events; or one for each panel
| on a dashboard. Here, you can hit the limit on a single page.
|
| I wrote a thin layer over my HTTP server's APIs which lets me
| write a single handler which can send events via either SSE or
| a websocket. Then, when i build a page, i use websockets, but
| if i want to debug, i can still use curl to make a normal HTTP
| request. Also, other apps can use SSE to pull data, which only
| requires an HTTP client, not a websocket client.
|
| [1] https://developer.mozilla.org/en-
| US/docs/Web/API/EventSource
| jraph wrote:
| I used both WebSockets and SSE. In one project, I even support
| WebSockets and a fallback working like what you describe.
|
| I'm sold on using SSE for pushed updates. But how is regular
| requests + SSE easier on the server compared to WebSockets? It
| seems like an open connection to maintain in both cases plus
| additional http request for the SSE+requests case.
| schmichael wrote:
| What is the advantage of SSE over streaming ndjson?
| paulddraper wrote:
| Built-in client API for parsing and event dispatching. Data
| doesn't have to be JSON encoded.
|
| But fundamentally nothing that Comet, steaming XHR, etc,
| WebSockets, can't do.
| [deleted]
| collaborative wrote:
| Not really related, but this is GAE's missing feature IMO
| [deleted]
| spullara wrote:
| SSE is phenomenal and underutilized because it wasn't supported
| by IE.
| asynchronous wrote:
| Love to see stuff like this on the HN front page, when I know
| tons of web devs that have never even heard of SSE.
|
| Tangentially, I'm having a massive problem with SSE datastreams
| erroring out about two minutes in for "ERR: Network chunk
| encoding" reasons, anyone else seen this before?
| no_wizard wrote:
| Try sending the messages without compression. A lot of servers
| don't know how to handle this for SSE (since its a uncommon
| content type)
___________________________________________________________________
(page generated 2023-05-15 23:02 UTC)