2

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?

tal
  • 35
  • 1
  • 1
  • 7

1 Answers1

2

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.

U Rogel
  • 1,893
  • 15
  • 30
  • 1
    @tallybee I just edited the answer and add the basic responses for the http and the ws connections. Hope it helps :) – U Rogel Jun 21 '20 at 08:55
  • 1
    Yes, thank you so much @cowCrazy !! Using different ports was the issue - this fixed it :) – tal Jun 21 '20 at 09:29