用socket.io发出事件的正确方法是什么?

时间:2018-09-18 12:45:20

标签: node.js socket.io

我想在长时间结束后向客户端发出事件。 这将在客户端显示带有链接的隐藏div。

这是我测试过的方法:

// server.js

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

require('./app/routes.js')(app, io);

// routes.js

app.post('/pst', function(req, res) {
        var url = req.body.convo;

        res.render('processing.ejs');

                myAsyncFunction(url).then(result => {
                    console.log('Async Function completed'); 

                    socket.emit('dlReady', { description: 'Your file is ready!'});

                    //do some other stuff here

        }).catch(err => {
                    console.log(err);
                    res.render('error.ejs');
         })
});

我明白了

ERROR: ReferenceError: socket is not defined

如果我将socket.emit()行更改为此:

io.on('connection', function(socket) {
    socket.emit('dlReady', { description: 'Your file is ready!'});
});

然后我没有收到任何错误,但是客户端没有任何反应。

这是客户端代码:

<script>
      document.querySelector('.container2').style.display = "none";
      var socket = io();
      socket.on('dlReady', function(data) { //When you receive dlReady event from socket.io, show the link part
        document.querySelector('.container1').style.display = "none";
        document.querySelector('.container2').style.display = "block";
      });
</script>

1 个答案:

答案 0 :(得分:1)

整个概念可能有点瑕疵。让我陈述一些有关此环境的事实,您必须完全了解这些事实,然后才能了解发生的情况:

  1. 浏览器执行POST时,浏览器中存在一个发布该帖子的页面。
  2. 如果该POST是从表单帖子(而不是页面中来自Javascript的帖子)发出的,则当您使用res.render()发送回信时,浏览器将关闭上一页并呈现新页面。
  3. 上一页中的任何socket.io连接都将关闭。如果res.render()中的新页面中包含Javascript,则当该Javascript运行时,它可能会或可能不会与服务器创建新的socket.io连接。无论如何,只有在调用res.render()之后的一段时间,这种情况才会发生,因为浏览器必须接收新页面,解析它,然后运行其中的Javascript,然后再将socket.io连接到您的服务器。
  4. 请记住,服务器可以处理许多客户端。它们是一对多的环境。因此,您很容易拥有成百上千个都与服务器建立了socket.io连接的客户端。因此,您的服务器永远无法假设存在一个socket.io连接,发送到该连接将转到特定页面。服务器必须跟踪N个socket.io连接。
  5. 如果服务器曾经希望发送到特定页面,则必须创建一种方法来弄清楚哪个socket.io connect属于它要向其发送的页面,获取该特定套接字并调用{{ 1}}仅在该特定套接字上。服务器永远无法通过创建一些名为socket.emit()的服务器范围的变量并使用它来执行此操作。多用户服务器永远无法做到这一点。
  6. “跟踪”给定客户端一次次返回服务器的通常方法是在客户端首次连接到服务器时设置唯一的cookie。从那时起,无论客户端是针对http请求的连接还是正在建立socket.io连接(也以http请求开头),从该客户端到您的服务器的每个连接(直到cookie过期或被浏览器删除)。 )将显示cookie,然后您可以从该cookie中分辨出它是哪个客户端。

因此,我对您的问题的理解是,您希望从客户端获取POST表格,将呈现的socket返回客户端,然后稍后再与您进行交流通过socket.io在客户端呈现页面。为此,必须执行以下步骤。

  1. 无论何时客户端向服务器发送POST,都必须确保有唯一的cookie发送回该客户端。如果cookie已经存在,则可以保留它。如果不存在,则必须创建一个新的。这可以手动完成,也可以使用processing.ejs来完成。我建议您使用express-session,因为它可以简化以下步骤,并且假设您正在使用express-session,我将概述步骤。
  2. 您的processing.ejs页面必须具有Javascript,该Javascript可与服务器建立socket.io连接,并为服务器将发出的“ dlready”消息注册消息侦听器。
  3. 您将需要在服务器上将express-session放入会话对象中的顶级io.on('connection', ...)。因为客户端可以从多个选项卡进行连接,所以如果您不希望这样做引起麻烦,则可能必须在会话对象中维护一组套接字。
  4. 您将需要在服务器上使用socket处理程序,以便在断开连接时将套接字从存储在其中的会话对象中删除。
  5. socket.on('disconnect', ...)处理程序中,当您准备发送app.post()消息时,必须在该页面的会话对象中为该浏览器找到合适的dlready并发出到那个插座。如果由于您呈现的页面尚未连接而没有连接,则必须等待它连接(要有效地执行此操作很棘手)。

如果POST请求来自页面中的Javascript,而不是来自表单发布,则事情会稍微简单一些,因为浏览器不会关闭当前页面并启动新页面,因此当前的socket.io连接将保持联系。如果需要,您仍然可以使用客户端Javascript完全更改页面外观。我会推荐这个选项。