1

I am creating an application(Nuxtjs) and am having troubles determining a good approach for sending data to the API(expressjs) and retrieving real-time updates. It seems that i can create "bi-di" connections with both protocals [Server Sent Events(SSE) and Axios or Websocket(WS)].

Both technologies work with most of the browsers, so i do not see a need to add additional libraries such as socket.io - For those individuals that do not have a current browser (too bad).

The application is based on user input of form data/clicks. Other users are then notified/updated with the information. At which point, the user can respond and the chain goes on(Basic chat like flow some information will be exchanged quickly while some may not or ever).

In my experience, the user flow would rely more heavily on listening for changes than actually changing the data - hence why i'm considering SSE. Unfortunately, both protocols have their flaws.

Websockets:

  1. Not all components will require a WS to get/post information as such it doesn't make sense to upgrade a basic http connection at the additional server expense. Therefore another method other than WS will be required(Axios/SSR). Example: Checking to see if a user name exists
  2. Security firewalls may prevent WS for operating properly
  3. express-ws makes sockets easy on the API end
  4. I believe you can have more than 6 concurrent connections by one user (which may be pro and con)

Server Sent Events

  1. Seems like the technology is fading in favor of WS
  2. Listening to the events seem to be as easy as listening to events for WS
  3. No need to upgrade the connection but will have to use node-spdy within the expressjs API - This may also be a good implementation for WS due to multiplexing
  4. Little more backend code to setup http2 and emit the SSEs(Ugly code as well - so functions will be made)
  5. Limited to HTTP limitations (6 concurrent connections) which is a problem as the users could easily max this out(ie. having multiple chat windows open)

TLDR

The application will be more "feed" orientated with occasional posting(which can be handled by Axios). However, users will be listening to multiple "feeds" and the HTTP limitations will be a problem. I do not know what the solution would be because SSE seem like the better option as i do not need to continually handshake. If this handshake is truly inconsequential(which from everything i have read isn't the case) than WS is likely a better alternative. Unfortunately, there is soooo much conflicting information regarding the two.

Thoughts?

Paul R
  • 208,748
  • 37
  • 389
  • 560
Jujubes
  • 424
  • 1
  • 6
  • 36
  • What evidence do you have for "Security firewalls may prevent WS for operating properly"? I would think anything that gives WS an issue would probably give a long lasting SSE connection an issue too. WS was very specifically designed to be infrastructure compatible and has been around a long time. SSE is still not widely used. – jfriend00 Nov 07 '19 at 00:35
  • 1
    FYI, socket.io exists for features reasons not because of lack of browser support. People use it for the features it has, particularly active keep-alive, connection drop detection and auto-reconnect when connections drop. You can see the socket.io features you get here: [What socket.io adds over plain webSocket](https://stackoverflow.com/questions/38546496/moving-from-socket-io-to-raw-websockets/38546537#38546537). – jfriend00 Nov 07 '19 at 00:37
  • @jfriend00 ive read multiple sources that some (`ex: sophos firewall`) will drop the connection once the upgrade is initiated and subsequent events are fired.To find exact examples i would have to scour the internet(Again all the conflicting information is driving me crazy) – Jujubes Nov 07 '19 at 01:09
  • @jfriend00 `socket.io` definitely has some cool features. I think rooms is a neat one but considering that it has almost 100% support. Isnt native `WS` just as simple (assuming that the api supports what you need)? – Jujubes Nov 07 '19 at 01:12
  • Native ws is fine if you don't want auto-reconnect, don't want detection of a dead connection, don't want a messaging layer, etc... IMO, socket.io exists because many serious apps using ws end up wanting that stuff anyway. Oh, and some larger scale apps really appreciate the clustering support that socket.io has (using redis). – jfriend00 Nov 07 '19 at 03:11
  • Maybe there are some firewalls that are misbehaved for ws. But, don't go thinking that a long lasting http connection being used for SSE isn't going to have some compatibility issues too (particularly with proxies and with some firewalls that are trying to clean up what they think are dead connections). That's my point. Neither is perfect in that regard, but both work in most situations, so not really a reason to choose one over the other. – jfriend00 Nov 07 '19 at 03:22
  • @jfriend00 - im gathering from your responses that you believe socket.io is the way to go due to its "flexibility". Am I assuming correctly? – Jujubes Nov 07 '19 at 03:22
  • As I said before, if you find use for those features (which I have a personal opinion that most people do). It's just a Javascript layer on top of webSocket so it's not heavy weight. You can decide if you want to make use of its features or not. – jfriend00 Nov 07 '19 at 03:34
  • @jfriend00 - thanks – Jujubes Nov 07 '19 at 05:15

2 Answers2

0

SSE, Web Sockets, and normal HTTP requests (via AJAX or Fetch API) are all different tools for different jobs.

SSE

  • Unidirectional, from server to client.
  • Text-based data only. (Anything else must be serialized, i.e. JSON.)
  • Simple API, widely compatible, auto-reconnects, has built-in provision for catching up on possibly missed events.

Web Sockets

  • Bi-directional.
  • Text or binary data.
  • Requires you to implement your own meaning for the data sent.

Standard HTTP Requests

  • Client to Server or Server to Client, but only one direction at a time.
  • Text or binary data.
  • Requires extra effort to stream server-to-client response in realtime.
  • Streaming from client-to-server requires that the entire data be known at the time of the request. (You can't do an event stream, for example.)

How to decide:

  • Are you streaming event-like data from the server to the client? Use SSE. It's purpose-built for this and is a dead simple way to go.
  • Are you sending data in only one direction, and you don't need to spontaneously notify clients of something? Use a normal HTTP request.
  • Do you need to send bidirectional data with a long-term established connection? Use Web Sockets.

From your description, it sounds like either SSE or Web Sockets would be appropriate for your use case. I'd probably lean towards SSE, while sending the random API calls from the client with normal HTTP requests.

I do not know what the solution would be because SSE seem like the better option as i do not need to continually handshake. If this handshake is truly inconsequential(which from everything i have read isn't the case) than WS is likely a better alternative.

Keep in mind that you can simply configure your server with HTTP keep-alive, making this point moot.

Brad
  • 159,648
  • 54
  • 349
  • 530
  • Thanks for the details. Can you briefly explain how `HTTP keep-alive` would effect my decision. – Jujubes Nov 07 '19 at 02:07
  • I'm just correcting the assumption that you need make a TCP connection for each and every subsequent HTTP request. HTTP keep-alive allows the TCP connection to remain open and be reused for future requests. This is much more efficient if you're expecting more requests. You can configure your server to keep it open as long or as short as you'd like. 5 seconds is common for people loading web pages. For your use case, you might choose 5 minutes. – Brad Nov 07 '19 at 02:29
  • Thx!! - Can i use the single upgraded connection on different endpoints as i traverse through the app? if possible i assume i would need a library to make handling the switching easier? or would i simply use a combination of `get` requests to load the page content and then set up a new connection? - this is where my knowledge is very lacking - any advice is an absolute gem – Jujubes Nov 07 '19 at 02:35
  • You don't need to do anything... the underlying browser does all this already. Just change your server's configuration around HTTP keep-alive, to keep the connection open longer than its default. – Brad Nov 07 '19 at 03:10
-2

I personally avoid using websockets as a 2-way communication between client and server.

I try to use sockets to broadcast data from server to users or a single user(socket), so they can get real-time updates, but for the post requests from client to server I tend to use axios or something similar, because I don't want to pass sensitive data (like access keys etc) from client to server.

My data flow goes something like

  1. User posts data to the server using axios, SSE or whatever
  2. Backend server does what it has to and notifies socket that an event has occured
  3. Socket server then notifies who he has to

My problem with using sockets to send data from client to server is the authentication issue. Technically, you can't pass anything that is not available to client-side javascript through a socket, meaning that to authenticate the action you will have to send sensitive information through a websocket. This is an issue for multiple reasons - if your sensitive data can be accessed using client-side js, there is a bunch of attacks that can be done here. Also someone can listen to the communication between ws and client. This is why I use API calls (axios etc) and store sensitive data to http-only cookies.

So once server wants to notify the user that something has happened, you can easily do that by telling the websocket server to send the data to the user.

You also want to keep your API server stateless, meaning no sockets in your API. I use separate server just for websocket connections, and my API server and websocket server communicate using redis. Pub/sub is a really neat feature for internal server communication and state management.

And to answer your question regarding multiple connections - you can use a single connection between your websocket server and client, and broadcast data using channels. So one channel would be for notification feed, other channel could be for story feed etc.

I hope this makes sense to you. This stack has worked really good for me.

  • Thanks for the answer. Doesn;t `wss` take care of most of those security/authentication issues (`withCreditials:true`). Additionally, i am using sessions on the API – Jujubes Nov 07 '19 at 01:19
  • 2
    This answer is incredibly misinformed. There are no inherent security issues for web sockets that don't also exist for HTTP. You should be using HTTPS (which Web Sockets effectively run over). Additionally, the same authentication you're using to handle your API calls can handle your websocket calls. As far as stateless or not, the communication protocol you choose doesn't dictate how you use it. – Brad Nov 07 '19 at 01:26
  • @Brad I set my auth tokens inside httponly cookies, to prevent XSS attacks, above all. Httponly cookies are not exclusive to http, of course I would use https in production. Sockets do not have a way of reading httponly cookies in client to server communication. If you pass your auth tokens inside the websocket from client to server, it's a liability. I agree with you on the 2nd part, using wss does not make API not stateless, but in my experience some kind of state management is usually needed when handling sockets. But that's just related to the apps you build I guess. – stefan_thedev Nov 07 '19 at 15:08