web-dev-qa-db-fra.com

Comment configurer l'itinéraire pour le serveur websocket en express?

J'ai une configuration similaire à celle-ci:

var WebSocketServer = require("ws").Server,
    express = require("express"),
    http = require("http"),
    app = express(),
    server = http.createServer(app);

app.post("/login", login);
app.get("/...", callSomething);
// ...

server.listen(8000);


var wss = new WebSocketServer({server: server});

wss.on("connection", function(ws){
   // ...
});

Je voudrais placer le WebSocketServer sous un chemin spécifique qui peut par exemple être "...com/whatever". La question est de savoir comment définir le chemin? C'est possible?

28
0101

Vous voudrez utiliser l'option path:

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

Voir la documentation complète ici

37
Aaron Dufour

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

Installation:

npm i express-ws -S

Exemple de serveur HTTP:

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)

Exemple de serveur HTTPS:

[~ # ~] remarque [~ # ~] Je recommande fortement de créer des fonctionnalités telles que HTTPS, la compression et la mise en cache à l'aide d'un serveur intermédiaire entre NodeJS et Internet, par exemple Nginx, il fonctionne beaucoup plus efficacement et sa configuration sera plus facile à changer à l'avenir

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)

Exemple de client de navigateur:

// 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)
}
21
ujeenator

La réponse acceptée n'est plus valide et lancera Frame Header Invalid les erreurs. Pull Request # 885 .

Les chemins WS ont été supprimés comme Lpinca le dit:

Le problème ici est que chaque WebSocketServer ajoute un nouvel écouteur pour l'événement de mise à niveau sur le serveur HTTP et lorsque cet événement est émis, handleUpgrade est appelé sur tous les serveurs.

Voici le travail autour:

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();
  }
});
17
Quesofat

vous pouvez utiliser cette idée simple en plaçant les requêtes de socket entrantes comme middleware, ce que j'ai trouvé assez utile

dans votre app.js

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

maintenant mettre le middleware là-bas

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

ou, ce qui est évidemment un peu plus simple, ceci à la place:

app.ws=ws;

maintenant votre construction ws est disponible dans vos routeurs, par exemple:

// 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! :))' ));
        });
});

ou si vous l'avez attaché à votre application par 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)
        });
});

faites très attention à l'utilisation de "ws.once", et non de "ws.on", ou vous obtiendrez plusieurs connexions à de nouvelles instances de websocket.server à chaque demande.

À votre santé! :)

5
Ivan Kolyhalov

Pour s'appuyer sur l'approche d'Ivan Kolyhalov, il est possible d'accéder au WebSocketServer à partir de n'importe quel point de terminaison en l'affectant (ou à l'une de ses propriétés) à app.locals. Par conséquent, vous n'avez qu'à gérer la gestion des connexions au WebSocketServer dans server.js.

Dans le code ci-dessous, nous attribuons la propriété clients du WebSocketServer à app.locals, ce qui nous permet de diffuser/envoyer un message personnalisé à tous les clients connectés simplement en faisant une requête HTTP aux points de terminaison routés.

server.js

const { createServer } = require("http");
const express = require("express");
const WebSocket = require("ws");

const app = express();
app.use(express.json({ extended: false }));
app.use("/api/pets", require("./routes/api/pets"));

const port = process.env.PORT || 5000;
const server = createServer(app);
server.listen(port, () => console.info(`Server running on port: ${port}`));

const webSocketServer = new WebSocket.Server({ server });
webSocketServer.on("connection", (webSocket) => {

    console.info("Total connected clients:", webSocketServer.clients.size);

    app.locals.clients = webSocketServer.clients;
});

./ routes/api/pets.js

const router = require("express").Router();
const WebSocket = require("ws");

const broadcast = (clients, message) => {

    clients.forEach((client) => {

        if (client.readyState === WebSocket.OPEN) {

            client.send(message);
        }
    });
};

router.get("/dog", (req, res) => {

    broadcast(req.app.locals.clients, "Bark!");

    return res.sendStatus(200);
});

router.get("/cat", (req, res) => {

    broadcast(req.app.locals.clients, "Meow!");

    return res.sendStatus(200);
});

module.exports = router;
1
TheDarkIn1978