如何正确使用Node.JS中的Socket.IO在路由/ Heroku中使用?

时间:2016-05-20 17:29:55

标签: node.js socket.io

请原谅任何noobiness,我正在学习。 :)

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

  1. (已解决?请参见编辑3)要使用,我不能以socket开头。我必须从io开始,否则我会得到“ReferenceError:socket not defined。”我希望能够使用socket.broadcast.emit将事件发送给除当前用户之外的所有客户端。现在我不得不在客户端进行检查,如果它是当前用户则不执行该事件,并且由于我的项目进展不得不发出更多事件,因此它变得非常令人头痛。

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

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

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

  5. 仓/万维网

    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) {{ 1}}(app.js)。

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

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

    app.js

    app.set('socketio', io);

    这也使Heroku因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); 而工作,欢呼!我猜process.env.PORT有效,因为我用app.js初始化应用程序,我猜bin / www不会执行吗?

    我仍需要#1的帮助(使用socket.broadcast.emit)。

    编辑3:好吧,它花了整整一天的时间,但我相信我已经弄清楚了一个怪癖。当然我无法使用node app.js,它是在connect上给出的参数。我还需要跨不同路由访问套接字并找到this SO question。这就是我最终在battlefield.js做的事情:

    socket

    (注意:我拿出了很多自己的代码,所以我不知道这是否可以复制和粘贴,你应该检查socket是不是null)

    没有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; ,套接字在GET'/'上未定义。根据我的理解,页面必须首先呈现...奇怪的是200有时对我不起作用而500则起作用。我可以把它留在500,但这是一场比赛所以时间非常重要。

    我现在的问题是:

    这可以改进/我有没有办法在没有setTimeout的情况下做到这一点?我是否正确地使用此代码连接'客户端,并且我是否有效地使用Socket.IO(问题#4)?

    P.S。如果没有人回答^这些问题,我会编辑它,回答问题,并接受我的答案作为最佳答案。

1 个答案:

答案 0 :(得分:2)

在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('连接'事件在您的服务器端触发时,您知道您有一个新客户端要服务。

从服务器端发出一个事件,例如欢迎事件,使客户端加入特定的房间。一旦你在那个房间里有他们,你就可以听到发给那个房间的任何事件。

请参阅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');

可能不是您问题的最准确答案,但我希望它能帮助您朝着正确的方向前进。