[HN Gopher] You might not need WebSockets
___________________________________________________________________
You might not need WebSockets
Author : hntrl
Score : 390 points
Date : 2025-04-11 22:27 UTC (1 days ago)
(HTM) web link (hntrl.io)
(TXT) w3m dump (hntrl.io)
| Dwedit wrote:
| WebSockets can't go through proxies.
| kingforaday wrote:
| I think what you are getting at is that websockets aren't as
| simple as http traffic through a proxy, but you absolutely can
| use proxies and ws connections just fine and for a variety of
| reasons.
| Austizzle wrote:
| I've definitely used websockets through nginx
| hombre_fatal wrote:
| They even go through Cloudflare.
| pier25 wrote:
| or Fly.io
| paxys wrote:
| Says who?
| bastawhiz wrote:
| This isn't based on any facts
| andrewmcwatters wrote:
| https://nginx.org/en/docs/http/websocket.html
| mad_vill wrote:
| For all the other comments, parent is probably talking about
| forward proxies and to their point many forward/enterprise
| proxies have configurations which cause websockets to break and
| it is a pain to debug this if you have many enterprise
| customers.
| mappu wrote:
| Echoing this. At $DAYJOB some 5-10% of customers will fail to
| initiate a websocket connection, even over wss:// despite
| plain HTTPS requests working fine. This is a client-side
| issue with whatever outdated HTTP CONNECT implementation the
| enterprise has.
| gregors wrote:
| Works completely fine in Haproxy
| shadowangel wrote:
| I use them though nginx/cloudflare. they work fine.
| xiphias2 wrote:
| With HTTP streaming the browser shows that it's still loading
| data. Is there some mitigation for it after the initial loading?
| panic wrote:
| I'm guessing you would use JS to fetch() the stream resource
| separately.
| xiphias2 wrote:
| Sure, it would be just cool to not have to do that
| paxys wrote:
| Not sure what you mean. How else are you going to make the
| request if _not_ using fetch()?
| bob1029 wrote:
| You could use an iframe as well, with certain caveats.
| bob1029 wrote:
| The fetch API is asynchronous. The initial page load would
| deliver the payload that then initiates the streaming
| connection in the background.
| lxgr wrote:
| That sounds less like a problem with HTTP streaming (initiated
| from JavaScript) and more like a page with some hanging
| resource.
| almosthere wrote:
| I liked vert.x's strategy of seamlessly downgrading the form of
| connection based on what is available.
| winrid wrote:
| Vert.x is great! I'm missing it lately with Node. At least with
| Vert.x you get a stack trace when you block the event loop by
| accident...
| ramesh31 wrote:
| You probably do. Reliable SSE is a complete nightmare.
| koakuma-chan wrote:
| Why?
| notpushkin wrote:
| > Bonus: Making it easy with eventkit
|
| Why not just use SSE? https://developer.mozilla.org/en-
| US/docs/Web/API/Server-sent...
| kordlessagain wrote:
| SSE is the way to roll.
| gorjusborg wrote:
| The problem selects the solution.
|
| That said, I like SSE for unidirectional string-encoded
| events.
| supahfly_remix wrote:
| Do CDN, such as Cloudflare, support SSE? The last time I
| looked, they didn't, but maybe things have changed.
| bastawhiz wrote:
| Yes, they are
| hntrl wrote:
| I have a demo of this for CF workers https://github.com/hntrl
| /eventkit/tree/main/examples/workers...
|
| (it's not SSE in particular, but it demonstrates that you can
| have a long running stream like SSE)
| nyrikki wrote:
| 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.
| threatofrain wrote:
| 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.
| hntrl wrote:
| 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...
| extheat wrote:
| 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.
| jongjong wrote:
| 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.
| hntrl wrote:
| 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.
|
| https://en.wikipedia.org/wiki/Command%E2%80%93query_separati.
| ..
| koakuma-chan wrote:
| SSE does not require a separate connection, unlike
| WebSockets.
| kaoD wrote:
| MDN disagrees. See the huge red warning here
| https://developer.mozilla.org/en-
| US/docs/Web/API/EventSource
|
| Unless you mean on HTTP2? But aren't WS connections also
| multiplexed over HTTP2 in that case?
| koakuma-chan wrote:
| > MDN disagrees. See the huge red warning here
| https://developer.mozilla.org/en-
| US/docs/Web/API/EventSource
|
| 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.
| kaoD wrote:
| > There is RFC 8441 but I don't think it's actually
| implemented in the browsers.
|
| Found this:
| https://github.com/mattermost/mattermost/issues/30285
| koakuma-chan wrote:
| https://chromestatus.com/feature/6251293127475200
|
| It looks like it's supported in Chrome and Firefox but
| not in Safari.
| gorjusborg wrote:
| I don't know why everyone... proceeds to use their own
| experience as proof of what everyone needs.
|
| These are tools, not religions.
|
| Websockets have some real downsides if you don't need
| bidirectional comms.
| osigurdson wrote:
| Based on my read, this basically is SSE but doesn't use the
| same protocol.
| tbeseda wrote:
| 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
| hntrl wrote:
| 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
| notpushkin wrote:
| 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.
| notpushkin wrote:
| 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.
|
| [1]: https://www.npmjs.com/package/@microsoft/fetch-event-
| source
| apitman wrote:
| 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.
| shadowangel wrote:
| It's javascript, anything simple needs a framework.
| colesantiago wrote:
| One thing I couldn't get working with websockets is how do you
| keep websocket connections active during code deployments without
| disconnecting current connected clients?
|
| Sounds very tricky to me to get right even at scale.
| paxys wrote:
| The trick is to make the connection stateless, i.e. any client
| can connect to any server (just like plain HTTP). Then when
| there's a new deployment the websocket connection will be
| terminated and the client can reconnect instantly,
| automatically finding the next available server.
| hombre_fatal wrote:
| It's a minor point in the article, but sending a RequestID to the
| server so that you get request/response cycles isn't weird nor
| beyond the pale.
|
| It's pretty much always worth it to have an API like
| `send(message).then(res => ...)` in a serious app.
|
| But I agree. The upgrade request is confusing, and it's annoying
| how your websocket server is this embedded thing running inside
| your http server that never integrates cleanly.
|
| Like instead of just reusing your middleware that reads
| headers['authorization'] from the websocket request, you access
| this weird `connectionParams` object that you pretend are request
| headers, heh.
|
| But the idiosyncrasies aren't that big of a deal (ok, I've just
| gotten used to them). And the websocket browser API is nicer to
| work with than, say, EventSource.
| syspec wrote:
| It's a good well worn tactic. You list in very high detail
| every single step of any process you don't like. It makes that
| process seem overly complex, then you can present your
| alternative and it sounds way simpler.
|
| For example, making a sandwich: You have to retrieve exactly
| two slices of bread after finding the loaf in the fridge. Apply
| butter uniformly after finding the appropriate knife, be sure
| to apply about a 2.1mm level of coating. After all of that you
| will still need to ensure you've calibrated the toaster!"
| jongjong wrote:
| Pretty much. In this case, WebSockets is simpler to implement
| than HTTP2; it's closer to raw TCP, you just send and receive
| raw packets... It's objectively simpler, more efficient and
| more flexible.
|
| It's a tough sell to convince me that a protocol which was
| designed primarily for resource transfer via a strict,
| stateless request-response mode of interaction, with server
| push tacked on top as an afterthought is simpler than
| something which was built from the ground up to be
| bidirectional.
| bobmcnamara wrote:
| I fixed a few bugs in a WebSocket client and was blown away
| by the things they do to trick old proxies into not
| screwing it all up.
| fenesiistvan wrote:
| I would be interested in those tricks
| bobmcnamara wrote:
| A big one is 'masking' all client requests that a proxy
| can't effectively cache the response since the request
| always changes.
|
| The RFC explains it:
| https://datatracker.ietf.org/doc/html/rfc6455#section-5.3
| AtlasBarfed wrote:
| Aren't websockets the only way to some sort of actual
| multi-core and threaded code in JavaScript, or is it still
| subject to the single background thread limitation and it
| just runs like node does?
| nothrabannosir wrote:
| Do you mean web workers?
| https://developer.mozilla.org/en-
| US/docs/Web/API/Web_Workers...
| hombre_fatal wrote:
| On the other hand, we're doing the worse tactic of getting
| held up on the first tiny subheader instead of focusing on
| the rest of a decent article.
|
| Also, their alternative is just a library. It's not like
| they're selling a SaaS, so we shouldn't be mean spirited.
| NetOpWibby wrote:
| > ...we shouldn't be mean spirited.
|
| Am I on the right website? _checks URL_
|
| People find anything to be mean about on here.
| dizhn wrote:
| But it is frowned upon.
| waynesonfire wrote:
| Absolutely. The author conveniently leaves out the benefit
| that websockets enable ditching the frontend js code--
| included is the library the author is plugging. The backend
| shouldn't send back an error message to the frontend for
| rendering, but, instead, a rendered view.
| procaryote wrote:
| The loaf shouldn't be in the fridge, and 2.1mm is way too
| much butter, especially if applied before putting the bread
| in the toaster
| iandanforth wrote:
| Sandwich code review is what HN is for.
| dcow wrote:
| sanwy.ch is the name of the YC25 startup tackling AI
| sandwich tech.
| accrual wrote:
| I think we need a function that returns the correct
| butter height given the dimensions of the input bread. We
| may also need an object containing different kinds of
| bread and the ideal amount of butter for each depending
| on the absorbtion characteristics of the bread, etc. The
| user's preference for butter might also need to be
| another parameter.
| goosejuice wrote:
| Too much butter? You're not living if thats too much
| butter!
| plasma_beam wrote:
| You butter bread before it's toasted? My mind is honestly
| blown (as I move to kitchen to try this).
| hntrl wrote:
| > sending a RequestID to the server so that you get
| request/response cycles isn't weird nor beyond the pale.
|
| To me the sticking point is what if the "response" message
| never comes? There's nothing in the websocket protocol that
| dictates that messages need to be acknowledged. With
| request/response the client knows how to handle that case
| natively
|
| > And the websocket browser API is nicer to work with than,
| say, EventSource.
|
| What in particular would you say?
| hombre_fatal wrote:
| Yeah, you'd need a lib or roll your own that races the
| response against a timeout.
|
| Kind of like how you also need to implement app-layer
| ping/pong over websockets for keepalive even though tcp
| already sends its own ping/pong. -_-
|
| As for EventSource, I don't remember exactly, something
| always comes up. That said, you could say the same for
| websockets since even implementing non-buggy reconn/backaway
| logic is annoying.
|
| I'll admit, time for me to try the thing you pitch in the
| article.
| throwaway2037 wrote:
| I have only small experience programming with web sockets,
| but I thought the ping pong mechanism is already built into
| the protocol. Does it have timeout? Does it help at the
| application layer?
|
| Ref: https://developer.mozilla.org/en-
| US/docs/Web/API/WebSockets_...
| copperroof wrote:
| You only need to implement it yourself if you've
| catastrophically fucked up the concurrency model on the
| client or sever side and they can't respond out of band
| of whatever you're waiting on.
| koakuma-chan wrote:
| Discord implements its own heartbeat mechanism. I've
| heard websocket-native ping is somehow unreliable. Maybe
| in case the websocket connection is fine but something
| happened at the application layer?
| jand wrote:
| "Unreliable" is a bit harsh - the problem arises imho not
| from the websocket ping itself, but from the fact that
| client-side _and_ server-side need to support the
| ping/pong frames.
| rodorgas wrote:
| Native EventSource doesn't let you set headers
| ([issue](https://github.com/whatwg/html/issues/2177)), so
| it's harder to handle authentication.
| ricardobeat wrote:
| That's basically RPC over WS.
|
| This article conflates a lot of different topics. If your
| WebSocket connection can be easily replaced with SSE+POST
| requests, then yeah you don't need WebSockets. That doesn't
| mean there aren't a ton of very valid use cases (games,
| anything with real time two-way interactivity).
| koakuma-chan wrote:
| > games, anything with real time two-way interactivity
|
| No need for WebSockets there as well. Check out WebTransport.
| hntrl wrote:
| It even has mention as being the spiritual successor to
| WebSocket for certain cases in mdn docs:
|
| https://developer.mozilla.org/en-
| US/docs/Web/API/WebSockets_...
| almostnormal wrote:
| "if your application requires a non-standard custom
| solution, then you should use the WebTransport API"
|
| That's a pretty convincing use-case. Why use something
| standard if it can be non-standard custom instead!
| misiek08 wrote:
| Your projects require holistic and craft solutions.
| Simple, working ways are the wrong path!
| apitman wrote:
| WebTransport is great but it's not in safari yet.
| motorest wrote:
| > No need for WebSockets there as well. Check out
| WebTransport.
|
| Isn't WebTransport basically WebSockets reimplemented in
| HTTP/3? What point where you trying to make?
| koakuma-chan wrote:
| > Isn't WebTransport basically WebSockets reimplemented
| in HTTP/3?
|
| No.
| motorest wrote:
| > No.
|
| Thanks for your insight.
|
| It seems you need to urgently reach out to the people
| working on WebTransport. You seem to know better and
| their documentation contradicts and refutes your
| assertion.
|
| https://github.com/w3c/webtransport/blob/main/explainer.m
| d
| koakuma-chan wrote:
| Where does that document say that WebTransport is just
| WebSockets over HTTP/3? The only thing in common is that
| both features provide reliable bi-directional streams,
| but WebTransport also supports unreliable streams and a
| bunch of other things. Please read the docs. There is
| also RFC 9220 Bootstrapping WebSockets with HTTP/3, which
| is literally WebSockets over HTTP/3.
| lttlrck wrote:
| He said "basically" which should be interpreted as
| "roughly"? Then it seems his assert is roughly correct?
| Horusiath wrote:
| Last time I've checked none of the common reverse proxy
| servers (most importantly nginx) supported WebTransport.
| hliyan wrote:
| This is how I used to do it over TCP, 20 years ago: each
| request message has a unique request ID which the server echoes
| and the client uses to match against a pending request. There
| is a periodic timer that checks if requests have been pending
| for longer than a timeout period and fails them with an error
| bubbled up to the application layer. We even had an
| incrementing sequence number in each message so that the
| message stream can resume after a reconnect. This was all done
| in C++e, and didn't require a large amount of code to
| implement. I was 25 years old at the time.
|
| What the author and similar web developers consider complex,
| awkward or difficult gives me pause. The best case scenario is
| that we've democratized programming to a point where it is no
| longer limited to people with highly algorithmic/stateful
| brains. Which would be a good thing. The worst case scenario is
| that the software engineering discipline has lost something in
| terms of rigor.
| Tabular-Iceberg wrote:
| Every web browser already has a built in system for matching
| requests and responses and checking if requests have been
| pending too long. There is no need to reinvent the wheel.
|
| The real problem with the software engineering discipline is
| that we are too easily distracted from solving the actual
| business problem by pointless architecture astronautics. At
| best because of boredom associated with most business
| problems being uninteresting, at worst to maliciously
| increase billable hours.
| motorest wrote:
| > The real problem with the software engineering discipline
| is that we are too easily distracted from solving the
| actual business problem by pointless architecture
| astronautics.
|
| There are two pervasive themes in software engineering:
|
| - those who do not understand the problem domain
| complaining that systems are too complex.
|
| - those who understand the problem domain arguing that the
| system needs to be refactored to shed crude unmaintainable
| hacks and further support requirements it doesn't support
| elegantly.
|
| Your comment is in step 1.
| prox wrote:
| I am beginning to see this increasingly. Apps that make the
| most basic of mistakes. Some new framework trying to fix
| something that was already fixed by the previous 3
| frameworks. UX designs making no sense or giving errors that
| used to be solved. From small outfits (that's fair) to multi
| billion dollar companies (you should know better) , I feel
| that rigor is definitely lacking.
| crabmusket wrote:
| A framework was recently posted here where the author was
| comparing how great their Rust-to-WASM client side state
| management could handle tens of thousands of records which
| would cause the JS version of their code to stack
| overflow...
|
| ...and yes, the stack overflow in the JS version was
| trivially fixable and then the JS version worked pretty
| well.
| willtemperley wrote:
| There is a huge difference between guaranteeing algorithmic
| security of an endpoint, e.g. getting authentication correct,
| and anticipating every security issue that often has nothing
| to do with developer code. The former is possible, the latter
| is not. I understand the author here not wishing to deal with
| the websocket upgrade process - I would be surprised if there
| aren't zero-days lurking there somewhere.
| cryptonector wrote:
| IMAP uses request IDs.
| crabmusket wrote:
| > sending a RequestID to the server so that you get
| request/response cycles isn't weird nor beyond the pal
|
| There's even a whole spec for that: JSON-RPC, and it's quite
| popular.
| DadBase wrote:
| My HTTP streaming has slowed to more of a trickle the last couple
| of years.
| theteapot wrote:
| Reads like a series of strawman arguments if you replace
| "WebSockets" with socket.io. - "messages aren't
| transactional": You can process request and return a value to
| sender in socket.io application layer. Is that transactional
| enough? - "If you're sending messages that don't
| necessarily need to be acknowledged (like a heartbeat or keyboard
| inputs), then Websockets make a great fit". But socket.io has
| acknowledgements. - "When a new WebSocket connection is
| initiated, your server has to handle the HTTP "upgrade" request
| handshake.". You can bypass handshake and go straight to WS even
| in Websockets, and if you don't socket.io handles upgrade for you
| pretty nicely so you not parsing HTTP header ..
| hntrl wrote:
| It's a good thing I didn't then :shrug:
|
| Websockets are a web standard, socket.io is a userland
| framework
| theteapot wrote:
| It's like arguing web components suck because there is all
| these problems you need to solve, while pretending web
| component frameworks (React, Vue, Angular, ..) that solve all
| those problems don't exist.
| osigurdson wrote:
| >> If it wasn't, we couldn't stream video without loading the
| entire file first
|
| I don't believe this is correct. To my knowledge, video stream
| requests chunks by range and is largely client controlled. It
| isn't a single, long lived http connection.
| dangoodmanUT wrote:
| Correct
| EE84M3i wrote:
| I believe that's standard for Netflix, etc, but is it also true
| for plain webms and mp4s in a <video> tags? I thought those
| were downloaded in one request but had enough metadata at the
| beginning to allow playback to start before the file is
| completely downloaded.
| wewewedxfgdf wrote:
| Yes it is true.
|
| Browsers talking to static web servers use HTTP byte ranges
| requests to get chunks of videos and can use the same
| mechanism to seek to any point in the file.
|
| Streaming that way is fast and simple. No fancy technology
| required.
|
| For MP4 to work that we you need to render it as fragmented
| MP4.
| jofla_net wrote:
| Seconded, ive done a userland 'content-range'
| implementation myself. of course there were a few ffmpeg
| specific parameters the mp4 needed to work right still
| EE84M3i wrote:
| Why would the browser send byte range requests for video
| tags if it expects to play the file back linearly from
| beginning to end anyway? Wouldn't that be additional
| overhead/round-trips?
| koakuma-chan wrote:
| > Why would the browser send byte range requests for
| video tags if it expects to play the file back linearly
| from beginning to end anyway?
|
| Probably because byte range is required for seeking, and
| playing from the beginning is equivalent to seeking at 0.
|
| > Wouldn't that be additional overhead/round-trips?
|
| No because the range of the initial byte range request is
| the whole file (`bytes=0-`).
| EE84M3i wrote:
| My original comment was about the commenter I replied to
| saying:
|
| > To my knowledge, video stream requests chunks by range
| and is largely client controlled. It isn't a single, long
| lived http connection.
|
| Wouldn't a byte range request for the whole file fall
| under the "single, long lived http connection"? Sure it
| could be terminated early and another request made for
| seeking, but regardless the video can start before the
| whole file is downloaded, assuming it's encoded
| correctly?
| tedunangst wrote:
| The client doesn't want to eat the whole file, so it uses
| a range request for just the beginning of the file, and
| then the next part as needed.
| koakuma-chan wrote:
| The client would actually request the whole file and then
| terminate the request if the file is no longer needed.
| This is what browsers do at least.
| lxgr wrote:
| Both are possible, and in fact I could imagine not all
| servers being too happy with having to trickle data over
| a persistent HTTP connection through the entire length of
| the video, with an almost always full TCP send buffer at
| the OS level.
| koakuma-chan wrote:
| > Both are possible
|
| It is possible if you are in control of the client, but
| no browser would stream an mp4 file request by request.
|
| > with an almost always full TCP send buffer at the OS
| level
|
| This shouldn't be a problem because there is flow
| control. Also the data would probably be sent to the
| kernel in small chunks, not the whole file at once.
| lxgr wrote:
| > It is possible if you are in control of the client, but
| no browser would stream an mp4 file request by request.
|
| I believe most browsers do it like that, these days:
| https://developer.mozilla.org/en-
| US/docs/Web/Media/Guides/Au...
|
| > This shouldn't be a problem because there is flow
| control.
|
| It's leveraging flow control, but as I mentioned this
| might be less efficient (in terms of server memory usage
| and concurrent open connections, depending on client
| buffer size and other variables) than downloading larger
| chunks and closing the HTTP connection in between them.
|
| Many wireless protocols also prefer large, infrequent
| bursts of transmissions over a constant trickle.
| koakuma-chan wrote:
| > I believe most browsers do it like that, these days
|
| Nope. Browsers send a byte range request for the whole
| file (`0-`), and the correspoding time range grows as the
| file is being downloaded. If the user decided to seek to
| a different part of the file, say at byte offset 10_000,
| the browser would send a second byte range request, this
| time `10000-` and a second time range would be created
| (if this part of the file has not already been
| downloaded). So there is no evidence there that any
| browser would stream files in small chunks, request by
| request.
|
| > in terms of server memory usage
|
| It's not less efficient in terms of memory usage because
| the server wouldn't read more data from the filesystem
| than it can send with respect to the flow control.
|
| > concurrent open connections
|
| Maybe if you're on HTTP/1, but we live in the age of
| HTTP/2-3.
|
| > Many wireless protocols also prefer large, infrequent
| bursts of transmissions over a constant trickle.
|
| AFAIK browsers don't throttle download speed, if that's
| what you mean.
| lxgr wrote:
| Ah, interesting, I must have mixed it up/looked at range
| request based HLS playlists in the past. Thank you!
|
| > AFAIK browsers don't throttle download speed, if that's
| what you mean.
|
| Yeah, I suppose by implementing a relatively large
| client-application-side buffer and reading from that in
| larger chunks rather than as small as the media codec
| allows, the same outcome can be achieved.
|
| Reading e.g. one MP3 frame at a time from the TCP buffer
| would effectively throttle the download, limited only by
| Nagle's Algorithm, but that's probably still much too
| small to be efficient for radios that prefer to sleep
| most of the time and then receive large bursts of data.
| koakuma-chan wrote:
| Realistically you wouldn't be reading anything from the
| TCP buffer because you would have TLS between your app
| and TCP, and it's pretty much guaranteed that whatever
| TLS you're using already does buffering.
| lxgr wrote:
| That's effectively just another small application layer
| buffer though, isn't it? It might shift what would
| otherwise be in the TCP receive buffer to the application
| layer on the receiving end, but that should be about all
| the impact.
| koakuma-chan wrote:
| Oh you're right, I'm just so used to making the TLS
| argument because there is also the cost of syscalls if
| you make small reads without buffering, sorry xD
| tsimionescu wrote:
| Are you sure browsers would try to download an entire,
| say, 10h video file instead of just some chunks of it?
| koakuma-chan wrote:
| Common sense tells me there should be some kind of limit,
| but I don't know what it is, whether it's standardized
| and whether it exists. I just tested and Firefox
| _buffered_ (according to the time range) the first
| 27_000~ seconds, but in the dev tools the request
| appeared as though still loading. Chrome downloaded the
| first 10.2 MB (according to dev tools) and stopped (but
| meanwhile the time range was growing from zero
| approximately by one second every second, even though the
| browser already stopped downloading). After it played for
| a bit, Chrome downloaded 2.6 more MB _using the same
| request_. In both cases the browser requested the whole
| file, but not necessarily downloaded the whole file.
| koakuma-chan wrote:
| > Wouldn't a byte range request for the whole file fall
| under the "single, long lived http connection"?
|
| Yes, it would (though a better description would be "a
| single, long lived http request" because this doesn't
| have anything to do with connections), and wewewedxfgdf
| also replied Yes.
|
| > Sure it could be terminated early and another request
| made for seeking, but regardless the video can start
| before the whole file is downloaded, assuming it's
| encoded correctly?
|
| Yes.
| wordofx wrote:
| It's not true because throwing a video file as a source on
| video tag has no information about the file being requested
| until the headers are pushed down. Hell back in 2005 Akamai
| didn't even support byte range headers for partial content
| delivery, which made resuming videos impossible, I believe
| they pushed out the update across their network in 06 or
| 07.
| jonathanlydall wrote:
| If your HTTP server provides and supports the appropriate
| headers and you're serving supported file types, then it
| absolutely is true.
|
| Just putting a url in my Chromium based browser's address
| bar to an mp4 file we have hosted on CloudFlare R2 "just
| works" (I expect a video tag would be the same),
| supporting skipping ahead in the video without having to
| download the whole thing.
|
| Initially skipping ahead didn't work until I disabled
| caching on CloudFlare CDN as that breaks the "accept-
| range" capability on videos. For now we have negligible
| amount of viewership of these mp4s, but if it becomes an
| issue we'll use CloudFlare's video serving product.
| wordofx wrote:
| > If your HTTP server provides and supports the
| appropriate headers and you're serving supported file
| types, then it absolutely is true.
|
| No. When you play a file in the browser with a video tag.
| It requests the file. It doesn't ask for a range. It does
| use the range if you seek it, or you write the JavaScript
| to fetch based on a range. That's why if you press play
| and pause it buffers the whole video. Only if you write
| the code yourself can you partially buffer a while like
| YouTube does.
| bmacho wrote:
| Nah, it uses complex video specific logic and http range
| requests as protocol. (At least the normal browsers and
| servers. You can roll your own dumb client/server of
| course.)
|
| > That's why if you press play and pause it buffers the
| whole video.
|
| Browsers don't do that.
| jonathanlydall wrote:
| Obviously it doesn't initially ask for a range if it
| starts from the beginning of the video, but it starts
| playing video immediately without requiring the whole
| file to download, when you seek it cancels the current
| request and then does a range request. At no point does
| it "have" to cache the entire file.
|
| I suppose if you watch it from start to finish without
| seeking it might cache the entire file, but it may
| alternatively keep a limited amount cached of the video
| and if you go back to an earlier time it may need to re-
| request that part.
|
| Your confidence seems very high on something which more
| than one person has corrected you on now, perhaps you
| need to reassess the current state of video serving,
| keeping in mind it does require HTTP servers to allow
| range requests.
| creatonez wrote:
| Who cares what happened in 2005? This is so rare
| nowadays, I've only really seen it on websites that are
| constructing the file as they go, such as the Github zip
| download feature.
| wewewedxfgdf wrote:
| You can learn it here:
|
| https://www.zeng.dev/post/2023-http-range-and-play-
| mp4-in-br...
|
| You can also watch it happen - the Chrome developer tools
| network tab will show you the traffic that goes to and
| from the web browser to the server and you can see this
| process in action.
| maccard wrote:
| 2005 is basically the dark ages of the web. It's pre Ajax
| and ie6 was the dominant browser. Using this as an
| argument is like saying apps aren't suitable because the
| iPhone didn't have an App Store until 2008.
|
| > It's not true because throwing a video file as a source
| on video tag has no information about the file being
| requested until the headers are pushed down.
|
| And yet, if you stick a web server in front of a video
| and load it in chrome, you'll see just that happening.
| wordofx wrote:
| Can load a video into a video tag in chrome. Press play
| and pause. See it makes a single request and buffers the
| whole video.
| maccard wrote:
| If you stick: <video controls>
| <source src="/video/sample.mp4" type="video/mp4">
| Your browser does not support the video tag.
| </video>
|
| into a html file, and run it against this pastebin [0],
| you'll see that chrome (and safari) both do range
| requests out of the box if the fileis big enough.
|
| [0] https://pastebin.com/MyUfiwYE
| wordofx wrote:
| Tried it on a 800mb file. Single request.
| jofzar wrote:
| The long answer is "it depends on how you do it"
| unsurprisingly video and voice/audio are probably the most
| different ways that you can "choose" to do distribution
| bhhaskin wrote:
| This. You can't just throw it into a folder and have to
| stream. The web server has to support it and then there is
| encoding and formats.
| AnotherGoodName wrote:
| They can playback as loading as long as they are encoded
| correctly fwiw (faststart encoded).
|
| When you create a video from a device the header is actually
| at the end of the file. Understandable, it's where the file
| pointer was and mp4 allows this so your recording device
| writes it at the end. You must re-encoded with faststart
| (puts the moov atom at the start) to make it load reasonably
| on a webpage though.
| timewizard wrote:
| > Understandable, it's where the file pointer was and mp4
| allows this so your recording device writes it at the end.
|
| Yet formats like WAVE which use a similar "chunked"
| encoding they just use a fixed length header and use a
| single seek() to get back to it when finalizing the file.
| Quicktime and WAVE were released around nearly the same
| time in the early 90s.
|
| MP2 was so much better I cringe every time I have to deal
| with MP4 in some context.
| lxgr wrote:
| At the expense of quite some overhead though, right?
|
| MPEG-2 transport streams seem more optimized for a
| broadcast context, with their small frame structure and
| everything - as far as I know, framing overhead is at
| least 2%, and is arguably not needed when delivered over
| a reliable unicast pipe such as TCP.
|
| Still, being able to essentially chop a single,
| progressively written MPEG TS file into various chunks
| via HTTP range requests or very simple file copy
| operations without having to do more than count bytes,
| and with self-synchronization if things go wrong, is
| undoubtedly nicer to work with than MP4 objects. I
| suppose that's why HLS started out with transport streams
| and only gained fMP4 support later on.
| timewizard wrote:
| > and is arguably not needed when delivered over a
| reliable unicast pipe such as TCP.
|
| So much content ended up being delivered this way, but
| there was a brief moment where we thought multicast UDP
| would be much more prevalent than it ended up being. In
| that context it's perfect.
|
| > why HLS started out with transport streams and only
| gained fMP4 support later on.
|
| Which I actually think was the motivation to add fMP4 to
| base MP4 in the first place. In any case I think MPEG
| also did a better job with DASH technically but borked it
| all up with patents. They were really stupid with that in
| the early 2010s.
| immibis wrote:
| Multicast UDP is widely used - but not on the Internet.
|
| We often forget there are networks other than the
| Internet. Understandable, since the Internet is most
| open. The Internet is just an overlay network over ISPs'
| private networks.
|
| SCTP is used in cellphone networks and the interface
| between them and legacy POTS networks. And multicast UDP
| is used to stream TV and/or radio throughout a network or
| building. If you have a "cable TV" box that plugs into
| your fiber internet connection, it's probably receiving
| multicast UDP. The TV/internet company has end-to-end
| control of this network, so they use QoS to make sure
| these packets never get dropped. There was a write-up
| posted on Hacker News once about someone at a hotel
| discovering a multicast UDP stream of the elevator music.
| lxgr wrote:
| > If you have a "cable TV" box that plugs into your fiber
| internet connection, it's probably receiving multicast
| UDP.
|
| That's a good point: I suppose it's a big advantage being
| able to serve the same, unmodified MPEG transport stream
| from a CDN, as IP multicast over DOCSIS/GPON, and as
| DVB-C (although I'm not sure that works like that, as DVB
| usually has multiple programs per transponder/transport
| stream).
| apitman wrote:
| For MP4s the metadata is at the end annoyingly enough.
| AnotherGoodName wrote:
| MP4 allows the header at the start or the end.
|
| It's usually written to the end since it's its not a fixed
| size and it's a pain for recording and processing tools to
| rewrite the whole file on completion just to move the
| header to the start. You should always re-encode to move
| the header to the start for web though.
|
| It's something you see too much of online once you know
| about it but mp4 can absolutely have the header at the
| start.
| koakuma-chan wrote:
| You can `-movflags faststart` when encoding to place it at
| the beginning.
| tomsonj wrote:
| implementations may request the metadata range at the end
| in this case, if the content length is known
| lxgr wrote:
| For "VOD", that works (and is how very simple <video> tag
| based players sometimes still do it), but for live
| streaming, it wouldn't - hence the need for fragmented
| MP4, MPEG-DASH, HLS etc.
|
| It does work for simpler codecs/containers though:
| Shoutcast/Icecast web radio streams are essentially just
| endless MP3 downloads, optionally with some non-MP3
| metadata interspersed at known intervals.
| lxgr wrote:
| The two are essentially the same thing, modulo trading off
| some unnecessary buffering on both sides of the TCP pipe in
| the "one big download" streaming model for more TCP
| connection establishments in the "range request to refill the
| buffer" one.
| bob1029 wrote:
| Yea this works for mp4 and HN seems confused about how.
|
| The MOOV atom is how range requests are enabled, but the
| browser has to find it first. That's why it looks like it's
| going to download the whole file at first. It doesn't know
| the offset. Once it reads it, the request will be cancelled
| and targeted range requests will begin.
| ejoso wrote:
| Correct. HLS and Dash are industry standards. Essentially the
| client downloads a file which lists the files in various
| bitrates and chunks and the client determines which is best for
| the given connectivity.
| Mogzol wrote:
| And even if you are using a "regular" video format like mp4,
| browsers will still use range requests [1] to fetch chunks of
| the file in separate requests, assuming the server supports
| it (which most do).
|
| [1] https://developer.mozilla.org/en-
| US/docs/Web/HTTP/Guides/Ran...
| motorest wrote:
| > I don't believe this is correct.
|
| Yes, the statement is patently wrong. There are a few very
| popular video formats whose main feature is chunking through
| HTTP, like HTTP Live Streaming or MPEG-DASH.
| wewewedxfgdf wrote:
| I wrote a subsystem the other day that used websockets for a
| server to distribute video conversion tasks.
|
| After futzing with silly things like file transfers and
| communication protocols I chucked it out and rewrote it so the
| client does HTTP long polling of the server and uploads its
| renders via hTTP POST.
|
| So much easier.
| ricardobeat wrote:
| That used to be called "Comet" back in the early 2000s.
|
| Did you try using an established library like socket.io,
| connectRPC etc? They handle a lot of the complexity.
| wewewedxfgdf wrote:
| Long polling is easy - all it means is your server does not
| immediately respond - nothing more to it than that.
| noduerme wrote:
| Long polling is great for most things that don't need a
| realtime push. It just gets to be a strain on a server if
| you've got to set up and tear down lots of those connections
| from lots of users. Keeping a socket alive is a lot less
| resource intensive. Maybe it sounds stupid, but I've even
| converted PHP code that responded to long polling to _handle
| the same polling over a socket_ to save resources. Most of my
| apps that need some kind of lazy updates actually work this
| way, and fall back to REST polling the same services if the
| socket is down.
| RajT88 wrote:
| The world needs more of these "you might not need" articles.
|
| Too many technology fads make things needlessly complicated, and
| complexity makes systems unreliable.
|
| You might not need Kubernetes
|
| You might not need The Cloud
|
| You might not need more than SQLite
|
| ...and so on.
| morsecodist wrote:
| Genuine question because I agree that there are a lot of over
| complicated systems. I often see people say all you need is
| SQLite. Do you implement replication yourself? Or you are just
| accepting that if something happens to your server your data is
| just gone? I always default to managed Postgres and that seems
| to be the simplest most boring solution.
| DrFalkyn wrote:
| Replication in SQLLite cp data.db <backuo
| location>
|
| On modern cloud systems you shouldn't have data loss anyway
| JSR_FDED wrote:
| There's a huge class of applications for which Litestream
| provides all the replication of SQLite databases you need.
|
| https://litestream.io
| https://github.com/benbjohnson/litestream
| immibis wrote:
| SQLite is absolutely not suitable if you need non-trivial
| amounts of write concurrency - SQLite locks the file when
| writing, and doesn't even notify the next writer when done -
| writers poll to see if it's unlocked yet. If you don't use
| WAL mode, then readers have to wait for writers to.
|
| You can still back up your SQLite database file. You
| shouldn't do it in the middle of a write, _or_ you should use
| the SQLite backup API to manage concurrency for you, _or_ you
| can back it up in SQL dump format. This isn 't one of the
| usual reasons you shouldn't use SQLite. If you need
| synchronous replication, then you shouldn't use SQLite.
|
| SQLite is robust against process crashes and even operating
| system crashes _if fsync works as it should_ (big if, if your
| data is important), but not against disk failure.
|
| In most of the cases when you shouldn't use SQLite, you
| should still just upgrade one step to Postgres, not some
| random NoSQL thing or Google-scale thing.
| lelanthran wrote:
| I'm still waiting for "You might not need React"
| socketcluster wrote:
| The problem with HTTP2 is that the server-push aspect was tacked
| on top of an existing protocol as an afterthought. Also, because
| HTTP is a resource transfer protocol, it adds a whole bunch of
| overheads like request and response headings which aren't always
| necessary but add to processing time. The primary purpose of
| HTTP2 was to allow servers to preemptively push files/resources
| to clients to avoid round-trip latency; to reduce the reliance on
| script bundles.
|
| WebSockets is a simpler protocol built from the ground up for
| bidirectional communication. It provides a lot more control over
| the flow of data as everything passes over a single connection
| which has a single lifecycle. It makes it a lot easier to manage
| state and to recover cleanly from a lost connection when you only
| have one logical connection. It makes it easier to process
| messages in a specific order and to do serial processing of
| messages. Having just one connection also greatly simplifies
| things in terms of authentication and access control.
|
| I considered the possibility of switching the transport to HTTP2
| for https://socketcluster.io/ years ago, but it's a fundamentally
| more complex protocol which adds unnecessary overheads and
| introduces new security challenges so it wasn't worth it.
| koakuma-chan wrote:
| How can server push be a problem with HTTP/2 if nobody supports
| server push? It's dead. And what about multiplexing and header
| compression? Not worth it?
| mountainriver wrote:
| Agree after banging my head against http2 for years, I now
| really enjoy how simple websockets are and their universal
| support
| tsimionescu wrote:
| Server push is dead though, SSE is a different idea with
| completely different semantics (and tradeoffs).
| alt227 wrote:
| > The primary purpose of HTTP2 was to allow servers to
| preemptively push files/resources to clients to avoid round-
| trip latency; to reduce the reliance on script bundles.
|
| The primary purpose for HTTP2 was to allow multiple
| simultaneous asynchoronous http calls, which is a massive
| loading performance boost for most websites. Server push was
| very much a tacked on afterthought.
| QuarterDuplex wrote:
| just use meteor.js https://www.meteor.com/ ?
| bmitc wrote:
| I personally view WebSockets as a nicer TCP that has all the
| messaging functionality you end up building anyway than as an
| alternative to HTTP.
| givemeethekeys wrote:
| > It makes your server code more complex.
|
| And, that is why we have frameworks to at least in the case of
| Web Sockets, make things as easy as regular old REST.
| collingreen wrote:
| Oof, what a headline to be top of hn the day after you implement
| websockets into a project.
| sampullman wrote:
| Websockets work great, don't worry too much about it.
| bonestamp2 wrote:
| We've had a production app with them for over 10 years and it's
| generally great. The only thing to be aware of is this Chrome
| bug:
|
| https://issuetracker.google.com/issues/362210027?pli=1
|
| You can add a recurring ping/pong between the client/server so
| you can know with some recency that the connection has been
| lost. You shouldn't have to do that, but you probably want to
| until this bug is fixed.
| philipwhiuk wrote:
| 60s heartbeat interval, job done.
|
| We've got multiple internal apps using WebSockets in
| production, for years. I have to say I don't really get all
| the concern in the article about upgrading the connection -
| any decent backend framework should handle this for you
| without a problem.
|
| Hacker News articles on new libraries generally live in the
| 1% of the 1%. For lots of websites, they don't need a web-
| socket because they are just doing CRUD. For the 1% doing
| live updates, web-sockets are great and straight-forward. For
| whatever specialised use case the article has, sure there's
| something even less well supported you can pivot to.
| sneilan1 wrote:
| Why do you need to implement your own web socket server? Why not
| use AWS appsync events?
| dgfitz wrote:
| I think at this point in my career my goal is to continue to
| never, ever, work on a public-facing website. 20 years into this
| foray of a career and I've avoided it so far.
| shusson wrote:
| The article forgot to mention websockets add state to the server!
| Load balancing will require sticking sessions. At scale this
| tends to mean separating websocket servers completely from http
| servers.
| toomim wrote:
| People interested in HTTP streaming should check out Braid-HTTP:
| https://braid.org. It adds a standard set of semantics that
| elegantly extend HTTP with event streaming into a robust state
| synchronization protocol.
| efortis wrote:
| You can also use long polling, which keeps alive a connection so
| the server can respond immediately when there's new data. For
| example:
|
| Server const LONG_POLL_SERVER_TIMEOUT = 8_000
| function longPollHandler(req, response) { // e.g. client
| can be out of sync if the browser tab was hidden while a new
| event was triggered const clientIsOutOfSync =
| parseInt(req.headers.last_received_event, 10) !== myEvents.count
| if (clientIsOutOfSync) { sendJSON(response,
| myEvents.count) return } function
| onMyEvent() { myEvents.unsubscribe(onMyEvent)
| sendJSON(response, myEvents.count) }
| response.setTimeout(LONG_POLL_SERVER_TIMEOUT, onMyEvent)
| req.on('error', () => { myEvents.unsubscribe(onMyEvent)
| response.destroy() })
| myEvents.subscribe(onMyEvent) }
|
| Client (polls when tab is visible) pollMyEvents()
| document.addEventListener('visibilitychange', () => { if
| (!document.hidden) pollMyEvents() })
| pollMyEvents.isPolling = false pollMyEvents.oldCount = 0
| async function pollMyEvents() { if
| (pollMyEvents.isPolling || document.hidden) return
| try { pollMyEvents.isPolling = true const
| response = await fetch('/api/my-events', { signal:
| AbortSignal.timeout(LONG_POLL_SERVER_TIMEOUT + 1000),
| headers: { last_received_event: pollMyEvents.oldCount }
| }) if (response.ok) { const nMyEvents =
| await response.json() if (pollMyEvents.oldCount !==
| nMyEvents) { // because it could be < or >
| pollMyEvents.oldCount = nMyEvents
| setUIState('eventsCount', nMyEvents) }
| pollMyEvents.isPolling = false pollMyEvents()
| } else throw response.status }
| catch (_) { pollMyEvents.isPolling = false
| setTimeout(pollMyEvents, 5000) } }
|
| Working example at Mockaton:
| https://github.com/ericfortis/mockaton/blob/6b7f8eb5fe9d3baf...
| hattmall wrote:
| Yep, have used long polling with no downsides for ~20 years.
| 95% of the time I see web sockets it's unnecessary.
| oneoverten wrote:
| What does this solve? Genuine question. You still have to manage
| connectivity, and synchronization. Also not so sure that stream
| reading will necessarily be quantized chunks of your updates sent
| from the server.
| djfobbz wrote:
| We have multiple mission-critical, industrial-grade WebSocket
| monitoring applications that have been running rock-solid for the
| last eight years without any hiccups in manufacturing
| environments. It seems like you're taking an easy-to-maintain
| codebase and turning it into a complex monstrosity.
| lxgr wrote:
| > We can't reliably say "the next message" received on the stream
| is the result of the previous command since the server could have
| sent any number of messages in between now and then.
|
| Doing so is a protocol decision though, isn't it?
|
| If the protocol specifies that the server either clearly
| identifies responses as such, or only ever sends responses, and
| further doesn't send responses out of order, I don't see any
| difference to pipelined HTTP: The client just has to count,
| nothing more. (Then again, if that's the use case, long-lived
| HTTP connections would do the trick just as well.)
| scheme271 wrote:
| What happens if a message somehow gets lost? Dropped packets,
| error, etc? Or is that completely precluded by using http
| streaming?
| lxgr wrote:
| TCP provides a lossless in-order stream, and errors are
| corrected at the layers even below that, so HTTP and
| WebSockets are equivalent in that regard.
| suzzer99 wrote:
| Me: For this POC you've given me, I will do an old-fashioned HTTP
| form submit, no need for anything else.
|
| Architect: But it must have websockets!
|
| Me: Literally nothing in this POC needs XHR, much less
| websockets. It's a sequential buy flow with nothing else going
| on.
|
| Architect: But it has to have websockets, I put them on the
| slide!
|
| (Ok he didn't say the part about putting it on the slide, but it
| was pretty obvious that's what happened. Ultimately I caved of
| course and gave him completely unnecessary websockets.)
| ticoombs wrote:
| I always try and push back on those beliefs, about reasonings
| why they believe it will be faster or more efficient than some
| other solution.
|
| I've found , if you could type cast those people, they would be
| a tech architect who only uses "web scale" items. (Relevant
| link: https://www.youtube.com/watch?v=5GpOfwbFRcs )
| suzzer99 wrote:
| I call them Powerpoint architects.
| kigiri wrote:
| My strategy for this kind of situation is to avoid direct
| rejection. Instead of saying stuff like "it's unnescessary" or
| "you are wrong", I push for trying first without.
|
| I would say:
|
| > Once we have a working MVP without websockets we can talk
| again to think about using websocket.
|
| Most times, once something is working, they then stop to care,
| or we have other priorities then.
| syntaxing wrote:
| Maybe I'm naive? But I thought its if you need stateful, use
| websockets. Else, use short/long poll or SSE.
| Spivak wrote:
| Discord and Slack do the article's suggestion of using web
| sockets for the receiving side only (mostly) and having you
| switch to http on the calling side. It works pretty well, you
| have to keep two sets of books but the web socket side is almost
| always for events that you, the client, should be responding to
| so it works somewhat like a reverse http but that works with your
| firewall. It also allows Discord to implement trivial, from the
| client's perspective, sharding. It really is clever as hell,
| scaling up a bot/integration is as easy as just turning on
| sharding and launching multiple instances of your bot. It handles
| spreading events across them.
|
| The author throws away their own suggestion but it clearly works,
| works well, and scales well into "supermassive" size. They don't
| even mention the real downside to web sockets which is that
| they're stateful and necessarily tied to a particular server
| which makes them not mesh at all with your stateless share-
| nothing http servers.
| 0xbadcafebee wrote:
| I just realized that modern web applications are a group form of
| procrastination. Procrastination is a complex thing. But
| essentially, it's putting something off because of some perceived
| pain, even though the thing may be important or even inevitable,
| and eventually the procrastination leads to negative outcomes.
|
| Web applications were created because people were averse to
| creating native applications, for fear of the pain involved with
| creating and distributing native applications. They were so
| averse to this perceived pain that they've done incredibly
| complex, even bizarre things, just so they don't have to leave
| the web browser. WebSockets are one of those things: taking a
| stateless client-server protocol (HTTP) and literally forcing it
| to turn into an entirely new protocol (WebSockets) just so people
| could continue to do things in a web browser that would have been
| easy in a native application (bidirectional stateful sockets, aka
| a tcp connection).
|
| I suppose this is a normal human thing. Like how we created cars
| to essentially have a horseless buggy. Then we created paved
| roads to make that work easier. Then we built cities _around_
| paved roads to keep using the cars. Then we built air-scrubbers
| into the cars and changed the fuel formula when we realized we
| were poisoning everyone. Then we built electric cars (again!) to
| try to keep using the cars without all the internal combustion
| issues. Then we built self-driving cars because it would be
| easier than expanding regional or national public transportation.
|
| We keep doing the easy thing, to avoid the thing we know we
| should be doing. And avoiding it just becomes a bigger pain in
| the ass.
| bonestamp2 wrote:
| I agree with a lot of that. But, it's a lot easier to get
| someone to try your web app than install a native app. It's
| also easier to get the IT department to allow an enterprise web
| app than install a native app. Web apps do have some advantages
| over native apps.
| crabmusket wrote:
| You left out the part where you explain why native apps are so
| much better for users and developers than web apps?
|
| I can't tell why you think WebSockets are so bizarre.
| koakuma-chan wrote:
| Many advantages, for example web apps get suspended if you're
| not browsing the tab. But I do agree it's much more
| attractive to write web apps mainly for portability.
| misiek08 wrote:
| Native apps also are suspended. Or can be, like na iOS (not
| being fanboy, I appreciate this mechanism). Also native,
| desktop apps also can be almost suspended while not used.
|
| Web apps are just way easier to do anything (rarely good),
| so many people are doing them without real engineering or
| algo knowledge producing trash every day. Article is also
| using same voice. Showing one protocol as completely bad,
| mentioning only the issues both approaches have, but
| silently omitting those issues describing ,,the only way,
| craft, holistic, Rust and WASM based solution, without a
| plug"
| koakuma-chan wrote:
| > Native apps also are suspended. Or can be, like na iOS
| (not being fanboy, I appreciate this mechanism).
|
| On iOS web apps get suspended very aggressively, and
| there is no way for a web app to signal to the browser to
| not suspend it. I never developed native mobile apps, but
| I assume it's less aggressive for native apps and/or
| native apps have a way to prevent themselves from being
| suspended. This doesn't seem to be an issue on desktop
| though.
| flomo wrote:
| > bidirectional stateful sockets, aka a tcp connection
|
| Which is not "easy" to do over the internet, so the native app
| folks ended-up using HTTP anyway. (Plus they invented things
| like SOAP.)
| SLWW wrote:
| I don't need them but I do like them.
|
| I see the shiny thing and I'm not delusional enough to think I
| need it.
| defanor wrote:
| I think an article like that would benefit from focusing more on
| protocols, rather than particular APIs to work with those:
| referencing the specifications and providing examples of
| messages. I am pretty sure that the article is about chunked
| transfer encoding [1], but it was not mentioned anywhere. Though
| possibly it tries to cover newer HTTP versions as well,
| abstracting from the exact mechanisms. In which case "JS API" in
| the title would clarify it.
|
| As for the tendency described, this seems to be an instance of
| the law of the instrument [2], combined with some instruments
| being more trendy than others. Which comes up all the time, but
| raising awareness of more tools should indeed be useful.
|
| [1] https://en.wikipedia.org/wiki/Chunked_transfer_encoding
|
| [2] https://en.wikipedia.org/wiki/Law_of_the_instrument
| andersmurphy wrote:
| You don't need websockets SSE works fine for realtime
| collaborative apps.
|
| Websockets sound great on paper. But, operationally they are a
| nightmare. I have had the misfortune of having to use them at
| scale (the author of Datastar had a similar experience). To list
| some of the challenges:
|
| - firewalls and proxies, blocked ports
|
| - unlimited connections non multiplexed (so bugs lead to ddos)
|
| - load balancing nightmare
|
| - no compression.
|
| - no automatic handling of disconnect/reconnect.
|
| - no cross site hijacking protection
|
| - Worse tooling (you can inspect SSE in the browser).
|
| - Nukes mobile battery because it hammers the duplex antenna.
|
| You can fix some of these problems with websockets, but these
| fixes mostly boil down to sending more data... to send more
| data... to get you back to your own implementation of HTTP.
|
| SSE on the other hand, by virtue of being regular HTTP, work out
| of the box with, headers, multiplexing, compression,
| disconnect/reconnect handling, h2/h3, etc.
|
| If SSE is not performant enough for you then you should probably
| be rolling your own protocol on UDP rather than using websockets.
| Or wait until WebTransport is supported in Safari (any day now ).
|
| Here's the article with a real time multiplayer Game of Life
| that's using SSE and compression for multiplayer.
|
| https://example.andersmurphy.com
|
| It's doing a lot of other dumb stuff explained a bit more here,
| but the point is you really really don't need websockets (and
| operationally you really don't want them):
|
| https://andersmurphy.com/2025/04/07/clojure-realtime-collabo...
| EarthLaunch wrote:
| Useful take, thanks for mentioning specifics. Some of these I
| wasn't aware of.
|
| - What makes load balancing easier with SSE? I imagine that
| balancing reconnects would work similar to WS.
|
| - Compression might be a disadvantage for binary data, which WS
| specializes in.
|
| - Browser inspection of SSE does sound amazing.
|
| - Mobile duplex antenna is way outside my wheelhouse, sounds
| interesting.
|
| Can you see any situation in which websockets would be
| advantageous? I know that SSE has some gotchas itself, such as
| limited connections (6) per browser. I also wonder about the
| nature of memory and CPU usage for serving many clients on WS
| vs SSE.
|
| I have a browser game (few players) using vanilla WS.
| andersmurphy wrote:
| Thanks.
|
| - Load balancing is easier because your connection is
| stateless. You don't have to connect to the same server when
| you reconnect. Your up traffic doesn't have to go to the same
| server as your down traffic. Websocket tend to come with a
| lot of connection context. With SSE you can easily kill
| nodes, and clients will reconnect to other nodes
| automatically.
|
| - The compression is entirely optional. So when you don't
| need it don't use it. What's great about it though is it's
| built into the browser so you're not having to ship it to the
| client first.
|
| - The connection limit of 6 is only applies to http1.1 not
| http2/3. If you are using SSE you'll want http2/3. But,
| generally you want http2/3 from your proxy/server to the
| browser anyway as it has a lot of performance/latency
| benefits (you'll want it for multiplexing your connection
| anyway).
|
| - In my experience CPU/memory usage is lower than websockets.
| Obviously, some languages make them more ergonomic to use
| virtual/green threads (go, java, clojure). But, a decent
| async implementation can scale well too.
|
| Honestly, and this is just an opinion, no I can't see when I
| would ever want to use websockets. Their reconnect mechanisms
| are just not reliable enough and their operational complexity
| isn't worth it. For me at least it's SSE or a proper gaming
| net code protocol over UDP. If your browser game works with
| websockets it will work with SSE.
| EarthLaunch wrote:
| I appreciate the answers. For others reading, I also just
| ran across another thread where you posted relevant info
| [0]. In the case of my game, I'm going to consider SSE,
| since most of the communication is server to client. That
| said, I already have reconnects etc implemented.
|
| In my research I recall some potential tradeoffs with SSE
| [1], but even there I concluded they were minor enough to
| consider SSE vs WS a wash[2] even for my uses. Looking back
| at my bookmarks, I see that you were present in the threads
| I was reading, how cool. A couple WS advantages I am now
| recalling:
|
| SSE is one-way, so for situations with lots of client-sent
| data, a second connection will have to be opened (with
| overhead). I think this came up for me since if a player is
| sending many events per second, you end up needing WS. I
| guess you're saying to use UDP, which makes sense, but has
| its own downsides (firewalls, WebRTC, WebTransport not
| ready).
|
| Compression in SSE would be negotiated during the initial
| connection, I have to assume, so it wouldn't be possible to
| switch modes or mix in pre-compressed binary data without
| reconnecting or base64-ing binary. (My game sends a mix of
| custom binary data, JSON, and gzipped data which the
| browser can decompress natively.)
|
| Edit: Another thing I'm remembering now is order of events.
| Because WS is a single connection and data stream, it
| avoids network related race conditions; data is sent and
| received in the programmatically defined sequence.
|
| 0: https://news.ycombinator.com/item?id=43657717
|
| 1: https://rxdb.info/articles/websockets-sse-polling-
| webrtc-web...
|
| 2: https://www.timeplus.com/post/websocket-vs-sse
| andersmurphy wrote:
| Cool. I didn't notice either. :)
|
| With http2/3 the it's all multiplexed over the same
| connection, and as far as your server is concerned that
| up request/connection is very short lived.
|
| Yeah mixed formats for compression is probably a use case
| (like you said once you commit with compression with SSE
| there's no switching during the connection). But, then
| you still need to configure compression yourself with
| websockets. The main compression advantage of SSE is it's
| not per message it's for the whole stream. The
| implementations of compression with websockets I've seen
| have mostly been per message compression which is much
| less of a win (I'd get around 6:1, maybe 10:1 with the
| game example not 200:1, and pay a much higher
| server/client CPU cost).
|
| Websockets have similar issues with firewalls and TCP. So
| in my mind if I'm already dealing with that I might as
| well go UDP.
|
| As for ordering, that's part of the problem that makes
| websockets messy (with reconnects etc). I prefer to build
| resilience into the system, so in the case of that demo I
| shared, if you disconnect/reconnect lose your connection
| you automatically get the latest view (there's no play
| back of events that needs to happen). SSE will
| automatically send up the last received event id up on
| reconnect (so you can play back missed events if you
| want, not my thing personally). I mainly use event ID as
| a hash of content, if the hash is the same don't send any
| data the client already has the latest state.
|
| By design, the way I build things with CQRS. Up events
| never have to be ordered with down events. Think about a
| game loop, my down events are basically a render loop.
| They just return the latest state of the view.
|
| If you want to order up events (rarely necessary). I can
| batch on the client to preserver order. I can use client
| time stamp/hash of the last event (if you want to get
| fancy), and the server orders and batches those events in
| sync with the loop, i.e everything you got in the last X
| time (like blockchains/trading systems). This is only for
| per client based ordering, no distributed client ordering
| otherwise you get into lamport clocks etc.
|
| I've been burnt too many times by thinking websockets
| will solve the network/race conditions for me (and then
| failing spectacularly), so I'd rather build the system to
| handle disconnects rather than rely on ordering
| guarantees that sometimes break.
|
| Again, though my experience has made me biased. This is
| just my take.
| realharo wrote:
| What do you mean by _" inspect in browser"_? All major
| browsers' devtools have supported WebSocket inspecting for many
| years.
|
| Many of the other issues mentioned are also trivial to solve
| (reconnects, cross-origin protection).
|
| Also, doesn't WebTransport have many of the same issues? (e.g.
| with proxies and firewalls). And do you have any data for the
| mobile battery claim? (assuming this is for an application in
| foreground with the screen on)
| andersmurphy wrote:
| The fact that you are saying they are trivial to solve means
| you probably need more visibility on your system. Reliable
| reconnect was the nightmare we saw regularly.
|
| Unfortunately, I can't go into much detail on the mobile
| battery stuff, but I can give you some hints. If you do some
| reading on how antenna on phones work combined with
| websockets heartbeat ping/pong and you should get the idea.
| Voultapher wrote:
| Having deployed WebSockets into production, I came to regret that
| over the next years. Be it ngnix terminating connections after
| 4/8 hours, browsers not reconnecting after sleep and other
| issues, I am of the opinion that WebSockets and other forms of
| long standing connections should be avoided if possible.
| bonestamp2 wrote:
| Not to mention, some major parts of the websocket API have been
| broken in Google Chrome for over two years now.
|
| Chrome no longer fires Close or Error events when a websocket
| disconnects (well, at least not when they happen, they get
| fired about 10 minutes later!). So, your application won't know
| for 10 minutes that the connection has been severed (unless the
| internet connection is also lost, but that isn't always the
| case when a websocket is disconnected).
|
| Here's the chrome bug:
|
| https://issuetracker.google.com/issues/362210027?pli=1
|
| From that bug report it looks like the Chrome bug is less than
| a year old, but the Chrome bug is originally mentioned here in
| April 2023 for a similar bug in iOS (the iOS bug has been
| resolved):
|
| https://stackoverflow.com/questions/75869629/ios-websocket-c...
|
| I kind of suspect Chrome is actually doing this intentionally.
| I believe they do this so a tab can recover from background
| sleep without firing a websocket close event. That's helpful in
| some cases, but it's a disaster in other cases, and it doesn't
| matter either way... it breaks the specification for how
| websockets are expected to work. WebSockets should always fire
| Close and Error events immediately when they occur.
| il-b wrote:
| I usually start with the long polling/SSE and migrate to
| WebSockets when needed. It is cheap and reliable with almost no
| performance overhead when compared to WebSockets.
| gabesullice wrote:
| This feels ill advised and I don't believe that HTTP streaming
| was designed with this pattern in mind
|
| Perhaps I'm wrong, but I believe HTTP streaming is for chunking
| large blobs. I worry that if you use this pattern and treat
| streaming like a pub/sub mechanism, you'll regret it. HTTP
| intermediaries don't expect this traffic pattern (e.g., NGINX,
| CloudFlare, etc.). And I suspect every time your WiFi connection
| drops while the stream is open, the fetch API will raise an error
| as if the request failed.
|
| However, I agree you probably don't need WebSockets for many of
| the ways they're used--server-sent events are a simpler solution
| for many situations where people reach for WebSockets... It's a
| shame SSEs never received the same fanfare.
| hobofan wrote:
| With the current AI/LLM wave SSE have received a lot of
| attention again, and most LLM chat frontends use them. At least
| from my perception as a result of this, support for SSEs in
| major HTTP server frameworks has improved a lot in the last few
| years.
|
| It is a bit of a shame though, that in order to do most useful
| things with SSEs you have to resort to doing non-spec-compliant
| things (e.g. send initial payload with POST).
| blensor wrote:
| Also MCP uses it
| ljm wrote:
| Same with graphql subscriptions.
|
| Arguably it's also because of serverless architecture where
| SSE can be used more easily than WS or streaming. If you want
| any of that on Lambda and API Gateway, for example, and
| didn't anticipate it right off the bat, you're in for quite a
| bit of pain.
| nkozyra wrote:
| SSE limitations in the browser are still a drag for this,
| too.
| skrebbel wrote:
| > I don't believe that HTTP streaming was designed with this
| pattern in mind
|
| > server-sent events are a simpler solution
|
| Fwiw Server-Sent Events are a protocol on top of HTTP
| Streaming.
|
| In fact I'm somewhat surprised that the article doesn't mention
| it, instead rolling their own SSE alternative that looks (to my
| non-expert eyes) like a lower level version of the same thing.
| It seems a bit weird to me to use chunks as a package boundary,
| I'd worry that that has weird edge cases (eg won't large
| responses be split into multiple chunks?)
| notjoemama wrote:
| Because of TCP, large chunks are always split into smaller
| chunks. It's just that at the HTTP level we don't know and
| don't see it. UDP forces people into designing their own
| protocols if the data is a defined package of bytes. Having
| done some socket coding my impression is web sockets would be
| good for a high end browser based game, browser based
| simulations, or maybe a high end trading system. At that
| point the browser is just a shell/window. As others have
| pointed out, there are already plenty of alternatives for web
| applications.
| jeroenhd wrote:
| The problem for things like video games and trading is that
| websockets only support TCP by default. Technologies like
| WebRTC allow for much faster updates.
|
| I think websockets certainly have their uses. Mostly in
| systems where SSE isn't available quickly and easily, or
| when sending a bunch of quick communications one after
| another as there's no way to know if the browser will
| pipeline the requests automatically or if it'll set up a
| whole bunch of requests.
| benwilber0 wrote:
| I pretty much always prefer SSE over websockets just because
| of the simplicity end-to-end. It's "just HTTP", so all the
| HTTP-based tech and tools apply out-of-the-box without any
| really special configuration that is required for WS. Curl
| (or even netcat) "just works", no special client. I don't
| have to do any special CDN configuration to proxy connections
| or terminate SSL aside from just turning off buffering.
|
| Websockets requires almost a completely new L7 stack and tons
| of special configuration to handle Upgrade, text or data
| frames, etc. And once you're out of "HTTP mode" you now have
| to implement the primitive mechanics of basically everything
| yourself, like auth, redirects, sessions, etc.
|
| It's why I originally made Tiny SSE which is a purpose-built
| SSE server written in Rust and programmable with Lua.
|
| https://tinysse.com
|
| https://github.com/benwilber/tinysse
| lxgr wrote:
| If you only care about events in one direction, it's a
| perfectly fine solution, but if you need something other
| than that, things might get awkward using SSE and regular
| HTTP calls, even with long-lived HTTP connections.
|
| > once you're out of "HTTP mode" you now have to implement
| the primitive mechanics of basically everything yourself,
| like auth, redirects, sessions, etc.
|
| WebSockets do support authentication via cookies or custom
| headers, don't they?
| VWWHFSfQ wrote:
| > WebSockets do support authentication via cookies or
| custom headers, don't they?
|
| It will depend on how the websocket architecture is
| implemented. A lot of systems will terminate the HTTP
| connection at the CDN or API gateway and just forward the
| upgraded TCP socket to the backend without any of the
| HTTP semantics intact.
| lxgr wrote:
| Interesting, do you have any examples for that? I haven't
| used WebSockets in such a context yet but was always
| curious how it would be exposed to the application
| servers.
| notatoad wrote:
| >If you only care about events in one direction, it's a
| perfectly fine solution
|
| i feel like clients sending requests to servers is a
| pretty well-solved problem with regular http? i can't
| imagine how that could be the difficult part of the
| equation.
| nitely wrote:
| not if you need bidirectional communication, for example
| a ping-pong of request/response. That is solved with WS,
| but hard to do with SSE+requests. The client requests may
| not even hit the same SSE server depending on your setup.
| There are workarounds obviously, but it complicates
| things.
| alt227 wrote:
| Everything 'just works', yet you needed to create your own
| server for it which needs scripting support?
|
| IMO 'just works' means Apache suupports it out of the box
| with a simple config file and you can just start sending
| messages to client IPs.
| benwilber0 wrote:
| "just works" in the sense that this is a complete SSE
| client application: while true; do
| curl example.com/sse | handle-messages.sh done
|
| Because it's just text-over-http. This isn't possible
| with websockets without some kind of custom client and
| layer 7 protocol stack.
| anamexis wrote:
| It's functional, but I wouldn't say it's complete without
| Last-Event-Id handling.
| ranger_danger wrote:
| My problem with SSE is that it has a very low connection
| limit of 6 per domain across the entire browser session.
| VWWHFSfQ wrote:
| That's an HTTP 1.1 problem, not SSE. Websockets has the
| same restriction.
| CharlieDigital wrote:
| You just use HTTP/2. It's a solved problem.
| osigurdson wrote:
| The issue I have with SSE and what is being proposed in this
| article (which is very similar), is the very long lived
| connection.
|
| OpenAI uses SSE for callbacks. That works fine for chat and
| other "medium" duration interactions but when it comes to fine
| tuning (which can take a very long time), SSE always breaks and
| requires client side retries to get it to work.
|
| So, why not instead use something like long polling + http
| streaming (a slight tweak on SSE). Here is the idea:
|
| 1) Make a standard GET call /api/v1/events (using standard
| auth, etc)
|
| 2) If anything is in the buffer / queue return it immediately
|
| 3) Stream any new events for up to 60s. Each event has a
| sequence id (similar to the article). Include keep alive
| messages at 10s intervals if there are no messages.
|
| 4) After 60s close the connection - gracefully ending the
| interaction on the client
|
| 5) Client makes another GET request using the last received
| sequence
|
| What I like about this is it is very simple to understand (like
| SSE - it basically is SSE), has low latency, is just a standard
| GET with standard auth and works regardless of how load
| balancers, etc., are configured. Of course, there will be
| errors from time to time, but dealing with timeouts / errors
| will not be the norm.
| thedufer wrote:
| I don't understand the advantages of recreating SSE yourself
| like this vs just using SSE.
|
| > SSE always breaks and requires client side retries to get
| it to work
|
| Yeah, but these are automatic (the browser handles it). SSE
| is _really_ easy to get started with.
| osigurdson wrote:
| My issue with eventsource is it doesn't use standard auth.
| Including the jwt in a query string is an odd step out
| requiring alternate middleware and feels like there is a
| high chance of leaking the token in logs, etc.
|
| I'm curious though, what is your solution to this?
|
| Secondly, not every client is a browser (my OpenAI / fine
| tune example is non-browser based).
|
| Finally, I just don't like the idea of things failing all
| time with something working behind the scenes to resolve
| issues. I'd like errors / warnings in logs to mean
| something, personally.
|
| >> I don't understand the advantages of recreating SSE
| yourself like this vs just using SSE
|
| This is more of a strawman and don't plan to implement it.
| It is based on experiences consuming SSE endpoints as well
| as creating them.
| VWWHFSfQ wrote:
| > it doesn't use standard auth
|
| I'm not sure what this means because it supports the
| withCredentials option to send auth headers if allowed by
| CORS
| osigurdson wrote:
| I mean Bearer / JWT
| CharlieDigital wrote:
| SSE can be implemented over HTTP GET; there is no
| difference in handling of JWT tokens in headers.
| thedufer wrote:
| > I'm curious though, what is your solution to this?
|
| Cookies work fine, and are the usual way auth is handled
| in browsers.
|
| > Secondly, not every client is a browser (my OpenAI /
| fine tune example is non-browser based).
|
| That's fair. It still seems easier, to me, to save any
| browser-based clients some work (and avoid writing your
| own spec) by using existing technologies. In fact, what
| you described isn't even incompatible with SSE - all you
| have to do is have the server close the connection every
| 60 seconds on an otherwise normal SSE connection, and all
| of your points are covered except for the auth one (I've
| never actually seen bearer tokens used in a browser
| context, to be fair - you'd have to allow cookies like
| every other web app).
| runeks wrote:
| > Perhaps I'm wrong, but I believe HTTP streaming is for
| chunking large blobs.
|
| You are wrong in the case of Chrome and Firefox. I have tried
| it and streaming e.g. unordered list elements are displayed
| instantly.
|
| But for Safari, "text/html" streaming happens in 512 byte
| chunks[1].
|
| [1] https://bugs.webkit.org/show_bug.cgi?id=265386
| lxgr wrote:
| GP is talking about intermediary proxies, CDNs etc. that
| might be unhappy about long-running connections with
| responses trickling in bit by bit, not doubting that it works
| on the client side.
|
| That said, I'd be surprised if proxy software or services
| like Cloudflare didn't have logic to automatically opt out of
| "CDN mode" and switch to something more transparent when they
| see "text/event-stream". It's not that uncommon, all things
| considered.
| z3t4 wrote:
| Web sockets are very low level, so first you want to use a
| library in order to work seamlessly with all 100 different
| implementations of websockets, but then you need to make your own
| protocol ontop of it. And implement ping and reconnect.
| austin-cheney wrote:
| WebSockets are full duplex, so both sides of a connection are
| equally transmitting sides. There first section fails to
| understands this and then builds some insane concern for state on
| top of this faulty notion. WebSockets don't care about your UI
| framework just like your car doesn't care what time you want to
| eat dinner.
|
| > You have to manage the socket lifecycle
|
| You have to do the very same thing with HTTP keep-alive or use a
| separate socket for each and every HTTP request, which is much
| slower. Fortunately the browser makes this stupid simple in
| regards to WebSockets with only a few well named events.
|
| > When a new WebSocket connection is initiated, your server has
| to handle the HTTP "upgrade" request handshake.
|
| If the author cannot split a tiny string on CRLF sequences they
| likely shouldn't be programming and absolutely shouldn't be
| writing an article about transmission. There is only 1 line of
| data you really need from that handshake request: _Sec-WebSocket-
| Key_.
|
| Despite the _upgrade_ header in the handshake the handshake is
| not actually HTTP. According to RFC6455 it is a tiny bit of text
| conforming to the syntax of RFC2616, which is basically just:
| lines separated by CRLF, terminated by two CRLFs, and headers
| separated from values with a colon. Really its just RFC822
| according to RFC2616.
|
| This is not challenging.
|
| I take it this article is written by a JavaScript framework
| junkie that cannot program, because there is so much in the
| article that is just wrong.
|
| EDITED: because people get sad.
| skrebbel wrote:
| You're very confrontational yet your post doesn't really refuse
| the author's main points.
|
| What the author means with "transactional" is that WebSockets
| have no built-in request-response mechanism, where you can tell
| which response belongs to which request. It's a weird word
| choice, but alas.
|
| I do agree that the bit about "handshakes are hard" feels a bit
| ill-advised btw, but it's not the core argument nor the core
| idea of this post. The core idea is "do request-response via
| HTTP, and then use some sort of single-direction stream (maybe
| over WS, doesn't matter) to keep client state in sync". This is
| a pretty good idea regardless of how well or how badly you know
| the WebSocket RFCs by heart.
|
| (I say this as someone who built a request-response protocol on
| top of websockets and finds it to work pretty well)
| austin-cheney wrote:
| > What the author means with "transactional" is that
| WebSockets have no built-in request-response mechanism
|
| Its not HTTP and does not want to be HTTP. In WebSockets the
| request/response mechanism is for one side to send a message
| and then the other side to send a message. If you want to
| associate a message from one side with a message from the
| other side put a unique identifier in the messages.
|
| If you really want the request/response round trip then don't
| use WebSockets. I would rather messages just transmit as each
| side is ready, completely irrespective of any round trip or
| response, because then everything is fully event oriented and
| free from directionality.
| skrebbel wrote:
| > If you really want the request/response round trip then
| don't use WebSockets.
|
| Yes! That's the whole point of the article! You agree with
| the author!
| jFriedensreich wrote:
| I don't know why the topic of websockets is so weird. 80% of the
| industry seem to have this skewed idealised perception of
| websockets as the next frontier of their web development career
| and cannot wait to use them for anything remotely connected to
| streaming/ realtime use cases. When pointing out the nuances and
| that websockets should actually be avoided for anything where
| they are not absolutely needed without alternatives people get
| defensive and offended, killing every healthy discussion about
| realistic tradeoffs for a solution. Websockets have a huge number
| of downsides especially losing many of the niceties and
| simplicity of http tooling, reasonability, knowledge and
| operations of http. As many here pointed, the goto solution for
| streaming server changes is h2 / h3 and SSE. Everything that can
| be accomplished in the other direction with batching and landing
| in the ballpark of max 0.5req/s per client does NOT need
| websockets.
| austin-cheney wrote:
| There is no reason to avoid WebSockets. This is a conclusion
| people come to because they are familiar with HTTP round trips
| and cannot imagine anything different.
|
| There are no nuances to understand. It's as simple as fire and
| forget.
|
| The only downside to WebSockets is that they are session
| oriented. Conversely, compared to WebSockets the only upside to
| HTTP is that its sessionless.
| ofrzeta wrote:
| Why not use a library like socket.io? It handles the socket
| lifecycle, reconnection etc.
| revskill wrote:
| Setinterval.
| manmal wrote:
| We are looking into adopting bidirectional streams, and have
| identified gRPC as a likely ideal candidate. It provides a layer
| on top of the blobs (partial responses) sent by either side, and
| takes over the required chunking and dechunking. And it doesn't
| have the authentication issues that Websockets have. I'd
| appreciate any insights on this matter.
| raluk wrote:
| Websocket is not ment to be sent as streams (TCP equvalent), but
| as datagrams aka packets (UDP equivalents). Correct me if I am
| wrong, but websockets api in Javascript libraray for browsers is
| pretty poor and does not have ability to handle backpressure and
| I am sure it can not handle all possible errors (assertions about
| delivery). If you want to use websockets as TCP streams including
| seasson handling, great care should be taken as this is not
| natively availabe in neither rfc6455 and in browser.
___________________________________________________________________
(page generated 2025-04-12 23:01 UTC)