【问题标题】:Express and WebSocket listening on the same portExpress 和 WebSocket 在同一个端口上侦听
【发布时间】:2016-04-20 22:05:25
【问题描述】:

我有一个 app.js 用于在收到一些 POST 数据时触发两个事件:

  1. 将 POST 数据插入数据库
  2. 使用 WebSocket 向客户端发送消息

这里是 app.js(只有重要的行)

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

这里是 server.js(只有重要的行)

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;

我想要实现的是将 WebSocketServer 设置为侦听应用程序的同一端口。 我想过将 server 变量从 app.js 传递给 server.js 但是

  1. 我认为这不是一种优雅的方式
  2. 我不知道该怎么做

你们怎么看?

【问题讨论】:

  • 你跳过了一些行。你没有mount express 应用上的 websocket 服务器?
  • 哦,回答你的问题。都是惯用的方式,为什么不优雅呢?需要(某事); myServer.mount(东西);像其他任何模块一样。
  • 我确实没有在 express 应用上安装 WebSocketServer,因为我不知道该怎么做。你能提供一个例子吗?感谢您的帮助!

标签: javascript node.js websocket


【解决方案1】:

根据您的代码和 cmets,这是一个超级简单的示例,说明它如何协同工作。

首先,http-server.js——一个典型的快递应用,只不过我们不以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;

现在,ws-server.js 示例,我们从节点本机 http.createServer() 创建 WSS 服务器。现在,请注意这是我们导入应用程序的地方,并为这个原生 http.createServer 提供应用程序实例以使用。

使用PORT=8080 node ws-server.js 启动应用程序:

注意您正在启动第二个,套接字相关的文件(ws-server)而不是第一个,http 相关的文件(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}`);
});

最后,这个示例 index.html 将通过创建 POST 和 Socket “请求”并显示响应来工作:

<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>

请注意,您需要一个相当新的浏览器,该浏览器同时具有用于该客户端部分的 WebSocket 和 fetch API,但无论如何这无关紧要,它只是为您提供了它的要点。

【讨论】:

  • 哇哦@Zlatko,这是一个地狱般的答案。非常感谢您为我花费的时间。非常感激!完美运行。
  • 好吧,我认为它不会惨败。一方面,请求 url 指的是相对路径,并且由于您从同一来源(在本例中为 localhost:8080)提供了文件,因此帖子也将随之而来。 websocket 也连接在那里。对于两个,这是 stackoverflow,并且该解决方案并不意味着按字面意思理解,仅作为概念证明。它会 。我真诚地希望您不要盲目地将代码从这里复制到您的工作中,而不阅读它,理解它然后调整您的代码。对于三个,是的,您肯定会使用反向代理。你太担心了;)
  • 我意识到我可以解决我的用例的方法是使用 webpack-dev-middleware 作为快速中间件,而不是添加 webpack-hot-middleware,而是通过编译器订阅 webpack 编译器事件.hooks.afterEmit 然后通过现有的自定义 websocket 服务器传递消息。
  • @Zlatko 相反,谢谢。整个网站上最好的答案之一。壮丽的。谢谢。
  • @Zlatko,非常感谢!杀了差不多一天才解决这个问题。
【解决方案2】:

http 和 ws 在同一个端口 80,“Amazing Zlatko Method™”。

您将拥有一个文件,比如 main.js,其中包含

 var app = express()

还有很多行的快速代码。

以通常的方式拥有尽可能多的中间件而无需更改是完全可以的。

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 ...

通常在该文件的末尾你会

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

删除那个。

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

Express 应用文件中没有其他更改

在你的 websocket 文件中,比如 multiplayer.js,你通常会有

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

其实改成

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);

在那个文件的末尾

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

注意! - 启动“multiplayer.js”文件(不是“main.js”)。

完美运行。很棒的东西。

【讨论】:

  • 这个设置也支持http吗?
  • 嗨@LenJoseph - 是的,100%,这就是重点!
  • 它在“server.on('request', app); ”部分对我来说失败了,因为传递的应用程序不是回调函数,而是一个对象(因为在您的示例中都不是)。你是如何让它发挥作用的?
  • @drecunion - 等等,你有没有注意到这个非常重要的一点:注意! - 启动“multiplayer.js”文件(不是“main.js”)。
  • @drecunion 这个答案有 7(七)个突出显示的代码示例。你做了(4)和(7)吗?
【解决方案3】:

以上所有答案都很好... 请找到下面的示例代码,看起来更简单一些

    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);
      });
    })

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 2015-04-17
    • 1970-01-01
    相关资源
    最近更新 更多