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

请原谅,我正在学习。 🙂

我有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 /端口引起的,我该如何正确地设置它,以及node app.js为什么工作?

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

斌/ 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; }; 

我很抱歉这么长的问题。 感谢您的任何帮助! 💜


编辑1:写出这个问题帮助我更好地理解这个问题。 我注释掉了server.listen(port); 在我的bin / www和nodemon现在工作。 然而,应用程序在Heroku上崩溃。 我的Procfile是web: node ./bin/www …是否需要改变?

编辑2:搞清楚Edit1和谷歌search后,我发现我不能有server.listen(); (bin / www) http.listen(3000); (app.js)。

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

在app.js中,为了清晰起见,我将var http = …更改为var server = …,并且监听了process.env.PORT || '3000'; process.env.PORT || '3000'; ,取自bin / www。 我也删除了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 ,它是连接上给出的参数。 我也需要通过不同的路线访问套接字,发现这个问题 。 这是我最终在battlefield.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? 我是否正确地使用这个代码“连接”客户端,并且是否有效地使用Socket.IO(问题4)?

PS如果没有人回答这些问题,我会编辑这个问题,回答问题,接受我的答案作为最佳答案。

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

当您导航到不同的名称空间(例如www.example.com – > http://www.example.com/some-name-space)时,您的前端variables将被删除,您需要重新发送它们。 如果你传递一个对象的同时GET请求的名字空间,这个效果很好。 但它不需要套接字。

它在你的路由器文件上这样做

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

对于套接字,最好的应用程序是单页面应用程序或replaceAJAX请求。 另外一个很好的sockets允许服务器能够在没有客户请求的情况下推送信息。

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

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

 $(document).ready(function() { 

当一个io.on('连接'事件触发你的服务器端,你知道你有一个新的客户端服务。

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

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

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