How to setup route for websocket server in express?

You'll want to use the path option:

var wss = new WebSocketServer({server: server, path: "/hereIsWS"});

See full documentation here


you could use this simple idea by putting incoming socket requests as a middleware, which I found to be pretty useful

in your app.js

const server = http.createServer(app)
const WebSocket = require('ws');
const ws = new WebSocket.Server({server});

now put middleware there

app.use(function (req, res, next) {
    req.ws = ws;
    return next();
});

or, which obviously is a bit simpler, this instead:

app.ws=ws;

now your ws construct is available in your routers, for example:

// main user dashboard GET
router.get('/', async function(req, res) {

        let ws = req.ws

        ws.once('connection', function connection(wss) {
            wss.on('message', function incoming(message) {
                console.log('received: %s', message);
            });

            wss.send(JSON.stringify('it works! Yeeee! :))' ));
        });
});

or if you attached it to your app by app.ws:

// main user dashboard GET
router.get('/', async function(req, res) {
    req.app.ws.once('connection', (wss) => {
            console.log('connected:', req.app.ws.clients.size)
        });
});

pay very close attention to usage of "ws.once", not "ws.on", or you'll get multiple connections at new instances of websocket.server on each request.

Cheers! :)


UPDATE Paths are valid in the ws server options.

interface ServerOptions {
        host?: string;
        port?: number;
        backlog?: number;
        server?: http.Server | https.Server;
        verifyClient?: VerifyClientCallbackAsync | VerifyClientCallbackSync;
        handleProtocols?: any;
        path?: string;
        noServer?: boolean;
        clientTracking?: boolean;
        perMessageDeflate?: boolean | PerMessageDeflateOptions;
        maxPayload?: number;
    }

The accepted answer is no longer valid and will throw Frame Header Invalid errors. Pull Request #885.

WS Paths were removed as Lpinca puts it:

The problem here is that each WebSocketServer adds a new listener for the upgrade event on the HTTP server and when that event is emitted, handleUpgrade is called on all servers.

Here is the work around:

const wss1 = new WebSocket.Server({ noServer: true });
const wss2 = new WebSocket.Server({ noServer: true });
const server = http.createServer();

server.on('upgrade', (request, socket, head) => {
  const pathname = url.parse(request.url).pathname;

  if (pathname === '/foo') {
    wss1.handleUpgrade(request, socket, head, (ws) => {
      wss1.emit('connection', ws);
    });
  } else if (pathname === '/bar') {
    wss2.handleUpgrade(request, socket, head, (ws) => {
      wss2.emit('connection', ws);
    });
  } else {
    socket.destroy();
  }
});

Use express-ws: https://www.npmjs.com/package/express-ws

Installation:

npm i express-ws -S

HTTP server example:

const express = require('express')
const enableWs = require('express-ws')

const app = express()
enableWs(app)

app.ws('/echo', (ws, req) => {
    ws.on('message', msg => {
        ws.send(msg)
    })

    ws.on('close', () => {
        console.log('WebSocket was closed')
    })
})

app.listen(80)

HTTPS server example:

NOTICE I strongly recommend making such features as HTTPS, compression and caching using an intermediate server between NodeJS and Internet, for example Nginx, it works much more efficiently and its configuration will be easier to change in the future

const https     = require('https')
const fs        = require('fs')
const express   = require('express')
const expressWs = require('express-ws')

const serverOptions = {
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
}

const app       = express()
const server    = https.createServer(serverOptions, app)

expressWs(app, server)

app.ws('/echo', (ws, req) => {
    ws.on('message', msg => {
        ws.send(msg)
    })

    ws.on('close', () => {
        console.log('WebSocket was closed')
    })
})

server.listen(443)

Browser client example:

// wss: protocol is equivalent of https: 
// ws:  protocol is equivalent of http:
// You ALWAYS need to provide absolute address
// I mean, you can't just use relative path like /echo
const socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:')
const echoSocketUrl = socketProtocol + '//' + window.location.hostname + '/echo/'
const socket = new WebSocket(echoSocketUrl);

socket.onopen = () => {
  socket.send('Here\'s some text that the server is urgently awaiting!'); 
}

socket.onmessage = e => {
  console.log('Message from server:', event.data)
}