【问题标题】:How to Properly Use Socket.IO in Node.JS for Use in Routes / with Heroku?如何在 Node.JS 中正确使用 Socket.IO 以用于路由/与 Heroku 一起使用?
【发布时间】:2016-05-20 17:29:55
【问题描述】:

请见谅,我正在学习。 :)

我已经设置了 Socket.IO,这样我就可以在我的路由中使用 io.sockets.emit,并且我可以正常工作。有一些问题。

  1. (已解决?查看编辑 3) 要使用,我不能以 socket 开头。我必须从 io 开始,否则我得到“ReferenceError:未定义套接字”。我希望能够使用socket.broadcast.emit 将事件发送给除当前用户之外的所有客户端。现在,如果是当前用户,我必须在客户端进行检查以不执行该事件,并且随着项目的进行,我不得不发出更多事件,这变得非常头疼。

    李>
  2. (已解决,请参见编辑 1 和 2) 每次我进行服务器端更改时,我都必须使用 node app.js 运行应用程序并手动重新启动服务器。当我运行 nodemon 时,我得到“端口 3000 已在使用中”。我觉得这一定和以下有关……

  3. (已解决,请参阅编辑 2) 推送到 Heroku 时,我在 bin/www 和 app.js 中将以下代码中的端口从 3000 更改为 80,但确实如此不起作用(我可以在控制台中看到套接字的 404 错误)。如果这和 #2 是由在两个地方处理 http/ports 引起的,我该如何正确设置它以及为什么 node app.js 工作?

  4. 我只需要在下图(战场)的路线上运行Socket.IO即可。我已经用require('./routes/battlefield')(io) 做这个了吗?

bin/www

var app = require('../app');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);

app.js

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

app.set('socketio', io);
var battlefield = require('./routes/battlefield')(io);

battlefield.js

var express = require('express');
var router = express.Router();

var returnRouter = function(io) {
  router.get('/', function(req, res, next) {
    // other stuff
    io.sockets.emit('message', 'This works');
    socket.broadcast.emit('message', 'Socket is undefined');
  })
  return router;
};
module.exports = returnRouter;

我尝试将我的路由包装在io.on('connection', function (socket) { 中以便能够使用socket,而不是“套接字未定义”,该事件不会发生。

var returnRouter = function(io) {
  io.on('connection', function (socket) {
    router.get('/', function(req, res, next) {
      // other stuff
      socket.emit('message', 'This is never emitted');
    })
  })
  return router;
};

对于这么长的问题,我深表歉意。感谢您的任何帮助! ????


EDIT1:写出这个问题帮助我更好地理解了这个问题。我在我的 bin/www 中注释掉了server.listen(port);,nodemon 现在可以工作了。但是,该应用程序在 Heroku 上崩溃了。我的 Procfile 是 web: node ./bin/www... 需要更改吗?

EDIT2:在弄清楚Edit1和谷歌搜索后,我发现我不能拥有server.listen();(bin/www)http.listen(3000);(应用程序.js)。

在 bin/www 中,我删除了server.listen();

在 app.js 中,为了清楚起见,我将 var http = ... 更改为 var server = ... 并让它监听来自 bin/www 的 process.env.PORT || '3000';。我还删除了app.set('socketio', io);,因为它看起来好像什么都没做......我想知道它为什么在那里。

app.js

var app = require('express')();

var server = require('http').Server(app);
var io = require('socket.io')(server);
var port = process.env.PORT || '3000';
server.listen(port);

这也让 Heroku 工作,因为 process.env.PORT,万岁!我猜node app.js 起作用了,因为我正在使用 app.js 初始化应用程序,我猜你这样做时 bin/www 没有执行?

我仍然需要关于 #1 的帮助(使用 socket.broadcast.emit)????.

编辑 3: 好吧,我确实花了一整天的时间,但我相信我有一个怪癖。当然我不能使用socket,它是连接时给出的参数。我还需要跨不同路由访问套接字并找到this SO question。这就是我最终在 Battleground.js 中所做的:

var returnRouter = function(io) {
  var socket;
  router.get('/', authenticatedUser, function(req, res, next) {
    io.on('connection', function(client){
      socket = client;
    });

    // other stuff
    res.render('battlefield', {/* data */});
    setTimeout(function(){socket.emit('test', 'It works!')}, 500);
  });

  router.post('/', function(req, res, next) {
    // socket can be accessed
  });
  return router;
};
module.exports = returnRouter;

(注意:我取出了很多我自己的代码,所以我不知道这是否可以复制和粘贴,你可能应该检查套接字是否不为空)

如果没有setTimeout,则在 GET '/' 上未定义套接字。据我了解,页面必须首先呈现......奇怪的是,200 有时对我不起作用,而 500 则可以。我可以将其保留为 500,但这是为了游戏,所以时间非常重要。


我现在的问题是:

这可以改进吗/有没有办法在没有 setTimeout 的情况下做到这一点?我是否用这段代码正确地“连接”了客户端,我(上面的问题#4^)是否有效地使用了 Socket.IO?

附:如果没有人回答 ^ 这些问题,我将对此进行编辑,回答问题,并接受我的回答作为最佳答案。

【问题讨论】:

    标签: node.js socket.io


    【解决方案1】:

    当您在 Node 中进行路由时使用套接字时,它并没有那么有用。

    当您导航到不同的名称空间(例如 www.example.com --> www.example.com/some-name-space)时,您的前端变量将被删除,您需要重新发送它们。如果您将对象与对该名称空间的 GET 请求一起传递,这将非常有用。但它不需要套接字。

    在你的路由器文件上是这样完成的

    var canAlsoBePassed = {some: "things"};
    router.get('/', function(req, res, next) {
       res.render('index', { items: "Can be passed directly", variables: canAlsoBePassed });
    });
    

    对于套接字,最好的应用程序是用于单页应用程序或替换 AJAX 请求。套接字允许的另一个好处是服务器无需客户端请求即可推送信息。

    要回答你关于 SetTimeout 的问题,不,你不需要这个。

    确保在客户端运行的套接字脚本正在等待加载文档。

    $(document).ready(function() {
    

    当 io.on('connection' 事件在您的服务器端触发时,您知道您有一个新客户端要服务。

    从服务器端发出一个类似于欢迎事件的事件,使客户端加入一个特定的房间。一旦你将它们放在那个房间里,你就可以监听发送到那个房间的任何事件。

    查看socket.io官方信息

    自定义命名空间 要设置自定义命名空间,可以在服务器端调用 of 函数:

    var nsp = io.of('/my-namespace');
    nsp.on('connection', function(socket){
      console.log('someone connected'):
    });
    nsp.emit('hi', 'everyone!');
    On the client side, you tell Socket.IO client to connect to that namespace:
    
    var socket = io('/my-namespace');
    

    可能不是对您问题的最准确答案,但我希望它能将您推向正确的方向。

    【讨论】:

      猜你喜欢
      • 2019-12-22
      • 1970-01-01
      • 2012-05-31
      • 2019-10-17
      • 1970-01-01
      • 2018-10-06
      • 2019-05-28
      • 1970-01-01
      • 2016-01-02
      相关资源
      最近更新 更多