Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Websocket connection error: returns 101, but does not upgrade

I am setting up some websockets using ws library. I am struggling to set up authorisation using a handshake. I have added a route to our server to upgrade to a websocket connection like so:

    .get(
      '/chat',
    authorisationFunction,
    upgradeConnection,
    ),

The websocket server:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3030 }); 

This is the upgradeConnection function, which will run if authorisation is successful:

const upgradeConnection = (request, socket, head) => {
  return wss.handleUpgrade(request, request.socket, head, function done(ws) {
    return wss.emit('connection', ws, request);
  });
}

I also have a function that listens to messages:

function webSocketsServer() {
  wss.on('connection', (ws, request, client) => {
    ws.on('message', message => {
      ws.send(message);
    });
  });
}

A connection gets emitted, and from my server I get this response:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: QyVvqadEcI1+ALka6j2pLKBkfNQ=

but then immediately on my client I get the error “WebSocket connection to 'ws://localhost:3000/chat’ failed: Invalid frame header”.

But when I bypass the handshake and connect directly to my websocket server, I can send messages successfully. The error is only on the client and not on the backend. What am I missing?

like image 324
tal Avatar asked Oct 11 '25 20:10

tal


1 Answers

I am not 100% sure it is the only way but might help so I post it. Based on this answer I would go for a server that uses the same port for http and websocket connections. You can achieve it like this:

const { createServer } = require('http')
const ws = require('ws')
const express = require('express')

const app = express()

const server = createServer(app)

app.get('/', (req, res) => {
  res.send('I am a normal http server response')
})

const wsServer = new ws.Server({
  server,
  path: '/websocket-path',
})

wsServer.on('connection', (connection) => {
  connection.send('I am a websocket response')
})

server.listen(3030, () => {
  console.log(`Server is now running on http://localhost:3030`)
  console.log(`Websocket is now running on ws://localhost:3030/<websocket-path>`)
})

So your server listens on port 3030 for normal http requests. If it gets a websocket connection request on path '/websocket-path' it is passed to the the ws connection handler and from there you are good to go.

like image 59
U Rogel Avatar answered Oct 14 '25 08:10

U Rogel