Search code examples
node.jsexpressherokuwebsocket

Cannot connect to websocket server in Heroku


I have a Node.js server running in Heroku. It works otherwise well, but client cannot connect the websocket.

When attempting to connect to websocket, the first http get request is completed with status 200 OK. Server log shows that a request to route "/" has been made, but nothing after that. I'm not sure if the websocket server is running.

Client code (Built with React):

this.ws = new WebSocket('wss://totentanz.herokuapp.com/');

Server code (Built with Express and Node.js):

const express = require('express')
const app = express()
const port = process.env.PORT || 3002
const cors = require('cors')

app.use(express.json())
app.listen(port, () => {
  console.log(`Server started!`)
})

app.use(cors());

app.get('/', (req, res) => { res.send('Hello World') })

const { Server } = require('ws');
const wss = new Server({ server: app })
wss.on('connection', function connection(ws) {
 console.log("New connection")
...
})

Error message:

WebSocket connection to 'wss://totentanz.herokuapp.com/' failed:
Event {isTrusted: true, type: "error", target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
bubbles: false
cancelBubble: false
cancelable: false
composed: false
currentTarget: WebSocket {url: "wss://totentanz.herokuapp.com/", readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}
defaultPrevented: false
eventPhase: 0
isTrusted: true
path: []
returnValue: true
srcElement: WebSocket {url: "wss://totentanz.herokuapp.com/", readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}
target: WebSocket {url: "wss://totentanz.herokuapp.com/", readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}
timeStamp: 1077.5999999940395
type: "error"
[[Prototype]]: Event

If I try to create WebSocket server with port, it fails of course, since then both http and ws servers use the same port. In Heroku there is no possibility of using multiple ports.

Is there a way to confirm that ws server is running? What could be the problem here?

EDIT: I have found the problem, but I do not understand yet why it happens. This works:

const server = express()
.use(cors)
.use(express.json())
.listen(PORT, () => console.log(`Listening on ${PORT}`))

This doesn't:

const server = express()
server.use(cors)
server.use(express.json())
server.listen(PORT, () => console.log(`Listening on ${PORT}`))

Solution

  • I found a module called express-ws. It solved the problem. Now the working code looks like this:

    const express = require('express');
    const PORT = process.env.PORT || 3000;
    const cors = require('cors')
    const app = express()
    const expressWs = require('express-ws')(app);
    
    app
      .use(express.json())
      .listen(PORT, () => console.log(`Listening on ${PORT}`));
    app.use(cors())
    app.get('/', (req, res) => { res.send('Hello World') })
    ...
    app.ws('/', function (ws, req) {
      ws.on('message', function (rawdata) {
    ...
    expressWs.getWss().clients.forEach(function each(client) {
    ...
    })
    }})