A quick tutorial on setting up websockets on a react + express app. This tutorial assumes you already have a running react client and express server.
If you are new to websockets and would like to know how it works, I recommend reading this post - Websockets 101
WebSocket server
We'll be using ws package to setup the websocket server. First let's write a websocket setup function.
// setupWebSocket.js
const WebSocket = require("ws");
// accepts an http server (covered later)
function setupWebSocket(server) {
// ws instance
const wss = new WebSocket.Server({ noServer: true });
// handle upgrade of the request
server.on("upgrade", function upgrade(request, socket, head) {
try {
// authentication and some other steps will come here
// we can choose whether to upgrade or not
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit("connection", ws, request);
});
} catch (err) {
console.log("upgrade exception", err);
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
socket.destroy();
return;
}
});
// what to do after a connection is established
wss.on("connection", (ctx) => {
// print number of active connections
console.log("connected", wss.clients.size);
// handle message events
// receive a message and echo it back
ctx.on("message", (message) => {
console.log(`Received message => ${message}`);
ctx.send(`you said ${message}`);
});
// handle close event
ctx.on("close", () => {
console.log("closed", wss.clients.size);
});
// sent a message that we're good to proceed
ctx.send("connection established.");
});
}
Next we tie our setup function with our express server,
// app.js or bin/www, where you currently have express setup
// app should be your express app
const server = http.createServer(app);
// pass the same server to our websocket setup function
// the websocket server will the run on the same port
// accepting ws:// connections
setupWebSocket(server);
Time to test, I use a firefox plugin called Weasel to connect to socket and test, there are similar alternatives in chrome.
Try connecting to the socket and also check the server logs to see the output of console.log statements.
// connect to your express server host and port but using ws protocol
// for example
ws://localhost:3000
Let's add some more functionality to our server to check if individual client messages and broadcast messages are working fine.
Create the functions below in another file,
// pipeline.js, for some examples
// client specific messages
// each client gets an individual instance
function individualPipeline(ctx) {
let idx = 0;
const interval = setInterval(() => {
ctx.send(`ping pong ${idx}`);
idx++;
}, 5000);
return interval;
}
// braodcast messages
// one instance for all clients
function broadcastPipeline(clients) {
let idx = 0;
const interval = setInterval(() => {
for (let c of clients.values()) {
c.send(`broadcast message ${idx}`);
}
idx++;
}, 3000);
return interval;
}
Import these functions in to our setup file,
// setupWebSocket.js
function setupWebSocket(server) {
// ws instance
const wss = new WebSocket.Server({ noServer: true });
// hookup broadcast pipeline
broadcastPipeline(wss.clients);
wss.on("connection", (ctx) => {
/* ... */
const interval = individualPipeline(ctx);
/* ... */
// clear the interval on connection close event
ctx.on("close", () => {
console.log("closed", wss.clients.size);
clearInterval(interval);
});
}
Now use Weasel (or equivalent) and watch ping pong and broadcast messages. Connect from multiple tabs, and observe broadcast message appearing in sync in all tabs, while ping pong is specific to each client.
broadcast message 5
ping pong 0
broadcast message 4
I'll leave the link to client and server code on the final part as we are going to add more functionality to this.
We'll work on client side in Part-2.
Top comments (7)
For some reason the test connection in Weasel is not working for me. I keep getting "The Connection is Abruptly Closed or Couldn't be Opened ! CONNECTION CLOSED!" Does the URL and the protocol need to have WS in it? Or just the URL? Right now I have URL: ws://localhost:3001 and protocol: ws.
Protocol is optional, it's only needed if you are taking decisions on the server based on it's value.
Can you try connecting to wss://echo.websocket.org, it's an echo server and would return the messages posted to it. If this works, then the issue is on your localhost websocket server setup.
websocket.org/echo.html
Yeah, connecting to that URL works fine. I'll wait for the fifth article and compare my code to your's.
Maybe you can see something wrong. This is main file that kicks off the server. dev-to-uploads.s3.amazonaws.com/i/...
I didn't get it at first, but after staring at it for a while I think the reason is using
app.listen(port)
instead ofserver.listen(port);
Never realised before but found a good post about it at StackOverflow
I still have some cleaning up to do on the code, here's what I've done till now on server
That was definitely the issue! Thank you so much!
This server does not respond. FYI