简体   繁体   中英

Express and WebSocket listening on the same port

I have an app.js which is used to trigger two events when some POST data are received:

  1. Insert POST data into a database
  2. Send a message to a client using a WebSocket

Here is the app.js (only the important lines)

var express = require('express');
var bodyParser = require('body-parser');
var server = require('./server');

var app = express();
var port = process.env.PORT || 3000;

app.post('/server', server);

app.listen(port, function(){
  console.log('Slack bot listening');
});

And here is the server.js (only the important lines)

var db = require('./DB');
var WebSocketServer = require('ws').Server;

var insertData = function(req, res){

    var wss = new WebSocketServer({server: server});
    console.log('WebSocketServer created');
    wss.on('connection', function(wss){
        wss.send(JSON.stringify('Socket open'));
    });
    wss.on('close', function(){
        console.log('WebServerSocket has been closed');
    });
};

module.exports = insertData;

What I would like to achieve is to set the WebSocketServer in a way that it listen to the same port of the app. I thought about passing the server var from app.js to server.js but

  1. I think this a not an elegant way to do it
  2. I don't know how to do it

What do you guys think?

Based on your code and comments, here's a super simple example of how it would work together.

First, the http-server.js - a typical express app, except that we do not start the server with app.listen() :

'use strict';

let fs = require('fs');
let express = require('express');
let app = express();
let bodyParser = require('body-parser');

app.use(bodyParser.json());

// Let's create the regular HTTP request and response
app.get('/', function(req, res) {

  console.log('Get index');
  fs.createReadStream('./index.html')
  .pipe(res);
});

app.post('/', function(req, res) {

  let message = req.body.message;
  console.log('Regular POST message: ', message);
  return res.json({

    answer: 42
  });
});

module.exports = app;

Now, the ws-server.js example, where we create the WSS server from a node native http.createServer() . Now, note that this is where we import the app, and give this native http.createServer the app instance to use.

Start the app with PORT=8080 node ws-server.js :

( Note you're launching the second, socket related, file (ws-server) not the first, http related, file (http-server).)

'use strict';

let WSServer = require('ws').Server;
let server = require('http').createServer();
let app = require('./http-server');

// Create web socket server on top of a regular http server
let wss = new WSServer({

  server: server
});

// Also mount the app here
server.on('request', app);

wss.on('connection', function connection(ws) {
 
  ws.on('message', function incoming(message) {
    
    console.log(`received: ${message}`);
    
    ws.send(JSON.stringify({

      answer: 42
    }));
  });
});


server.listen(process.env.PORT, function() {

  console.log(`http/ws server listening on ${process.env.PORT}`);
});

Finally, this sample index.html will work by creating both a POST and a Socket "request" and display the response:

<html>
<head>
  <title>WS example</title>
</head>

<body>
  <h2>Socket message response: </h2>
  <pre id="response"></pre>
  <hr/>
  <h2>POST message response: </h2>
  <pre id="post-response"></pre>
  <script>

  // Extremely simplified here, no error handling or anything
document.body.onload = function() {

    'use strict';

  // First the socket requesta
  function socketExample() {
    console.log('Creating socket');
    let socket = new WebSocket('ws://localhost:8080/');
    socket.onopen = function() {

      console.log('Socket open.');
      socket.send(JSON.stringify({message: 'What is the meaning of life, the universe and everything?'}));
      console.log('Message sent.')
    };
    socket.onmessage = function(message) {

      console.log('Socket server message', message);
      let data = JSON.parse(message.data);
      document.getElementById('response').innerHTML = JSON.stringify(data, null, 2);
    };
  }

  // Now the simple POST demo
  function postExample() {

    console.log('Creating regular POST message');
  
    fetch('/', {  
      method: 'post',  
      headers: {  
        "Content-type": "application/json"  
      },  
      body: JSON.stringify({message: 'What is the meaning of post-life, the universe and everything?'})  
    })
    .then(response => response.json())  
    .then(function (data) {  
    
      console.log('POST response:', data);
      document.getElementById('post-response').innerHTML = JSON.stringify(data, null, 2);   
    })  
    .catch(function (error) {  
      console.log('Request failed', error);  
    });   
  }

  // Call them both;

  socketExample();
  postExample();
}
  </script>
</body>
</html>

Note you'll need a quite recent browser, one that has both WebSocket and fetch APIs for this client side part, but it's irrelevant anyway, it just gives you the gist of it.

http and ws on the same port 80, "Amazing Zlatko Method™."

You'll have a file, say main.js, with

 var app = express()

and many lines of express code.

It is perfectly OK to have as much middleware as you want in the usual way with no changes .

var app = express()
app.use(session(session_options))
app.use(passport.initialize())
app.use(passport.session())
app.use('/static', express.static('static'))
// etc etc
app.get ...
app.get ...
app.post ...
app.post ...

Normally at the end of that file you would

 app.listen(80, (err) => { ... })

Delete that.

 //app.listen(80, (err) => { ... })

No other changes in the express app file.

In your websocket file, say multiplayer.js, you would normally have

const WebSocket = require('ws');
const wss = new WebSocket.Server({
    port: 9999,
    perMessageDeflate: false
})

In fact, change to

const WebSocket = require('ws');
/*const wss = new WebSocket.Server({
    port: 2828,
    perMessageDeflate: false
});*/
let WSServer = WebSocket.Server;
let server = require('http').createServer();
let app = require('./main'); // note, that's your main.js file above
let wss = new WSServer({
  server: server,
  perMessageDeflate: false
})
server.on('request', app);

And at the end of that file

server.listen(80, function() {
    console.log(`Amazing Zlatko Method™ combo server on 80`);
});

Note! - launch the 'multiplayer.js' file ( not 'main.js').

It works perfectly. Amazing stuff.

All the above answers are quite nice... Please find the below sample code, seems a little simpler

    var express = require('express')
    var app = express()
    var http = require('http').createServer(app);
    var io = require('socket.io')(http);

    app.get('/', function (req, res) {
      res.sendFile(__dirname + '/index.html');
    });

    http.listen(process.env.PORT || 3000, function() {
      var host = http.address().address
      var port = http.address().port
      console.log('App listening at http://%s:%s', host, port)
    });

    io.on('connection', function(socket) {
      console.log('Client connected to the WebSocket');

      socket.on('disconnect', () => {
        console.log('Client disconnected');
      });

      socket.on('chat message', function(msg) {
        console.log("Received a chat message");
        io.emit('chat message', msg);
      });
    })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM