在 Express 4 和 express-generator 的 /bin/www 中使用 socket.io

IT技术 javascript node.js express socket.io
2021-01-12 04:13:20

所以这就是交易:我正在尝试在一个快速项目中使用 socket.io。Express Js 4 发布后,我更新了我的 express-generator,现在应用程序初始功能进入./bin/www文件,包括那些变量(www 文件内容:http : //jsfiddle.net/avMa5/

var server = app.listen(app.get('port'), function() {..}

(检查它npm install -g express-generator然后express myApp

话虽如此,让我们记住 socket.io 文档如何要求我们触发它:

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

好的,但我不能在 app.js 中做到这一点,就像推荐的那样。这应该在 ./bin/www 中完成才能工作。在 ./bin/www 这是我可以做的让它工作:

var io = require('socket.io')(server)

好的,这有效,但我不能在其他任何地方使用 io var,而且我真的不想将我的 socket.io 函数放在www文件中。

我想这只是基本语法,但我无法让它工作,甚至不能在 www 文件上使用module.exports = serverorserver.exports = servermodule.exports.io = app(io)

所以问题是:如何使用 socket.io 将此 /bin/www 文件作为我的应用程序的起点?

6个回答

以下是将 Socket.io 添加到新生成的 Express-Generator 应用程序的方法:

  1. 创建一个包含 socket.io 逻辑的文件,例如socketapi.js

socketapi.js:

const io = require( "socket.io" )();
const socketapi = {
    io: io
};

// Add your socket.io logic here!
io.on( "connection", function( socket ) {
    console.log( "A user connected" );
});
// end of socket.io logic

module.exports = socketapi;
  1. 修改您的bin/www启动器。有两个步骤:需要您的 Socket.io api 并在创建 HTTP 服务器后立即将 HTTP 服务器附加到您的 socket.io 实例:

垃圾箱/万维网:

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('socketexpress:server');
var http = require('http');
let socketapi = require("../socketapi"); // <== Add this line

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);
socketapi.io.attach(server); // <== Also add this line

(...)
  1. 然后你只需要在你的 index.html 中添加 Socket.io 客户端。</body>结束标记之前添加以下内容

索引.html

    (...)
    <script src="/socket.io/socket.io.js"></script>
    <script>
        var socket = io();
    </script>
</body>
</html>
  1. 最后你可以启动你的 Express 服务器:
  • 基于Unix: DEBUG=myapp:* npm start
  • 视窗: set DEBUG=myapp:* & npm start

注 1

如果由于某种原因,你需要访问您的套接字API app.js,那么你可以导入,而不是在你的套接字API app.js,并重新将其导出:

应用程序.js

var express = require('express');
var socketapi = require("./socketapi"); // <== Add this line
(...)
// You can now access socket.io through the socketapi.io object
(...)
module.exports = { app, socketapi }; // <== Export your app and re-export your socket API here

然后在您的bin/www启动器中,不要在自己的行中导入您的套接字 api,只需将其导入您的应用程序:

垃圾箱/万维网

var {app, socketapi} = require('../app'); // <== Import your app and socket api like this
(...)
var server = http.createServer(app);
socketapi.io.attach(server); // <== You still have to attach your HTTP server to your socket.io instance

注 2 此答案已更新以适用于最新的 Express Generator(撰写本文时为 4.16)和最新的 Socket.io(撰写本文时为 3.0.5)。

“……如果您愿意,甚至可以将其提供给您的路线。” 好的,但是如何?如果您能举例说明如何做到这一点,那就太好了。
2021-03-17 04:13:20
将自定义属性附加到对象上不是很糟糕app吗?最好使用符号或app.set().
2021-03-17 04:13:20
为什么app.io = io当你可以使用module.exports = { app, io },而不是
2021-03-17 04:13:20
这只是将 io 变量放入 app 对象的问题。也可以是: app.io = socket_io();
2021-04-01 04:13:20
@GabrielHautclocq 我如何从我的路线访问它?欣赏它!
2021-04-07 04:13:20

一种稍微不同的启动方法socket.io,它将所有相关代码组合在一个地方:

垃圾箱/万维网

/**
 * Socket.io
 */
var socketApi = require('../socketApi');
var io = socketApi.io;
io.attach(server);

socketApi.js

var socket_io = require('socket.io');
var io = socket_io();
var socketApi = {};

socketApi.io = io;

io.on('connection', function(socket){
    console.log('A user connected');
});

socketApi.sendNotification = function() {
    io.sockets.emit('hello', {msg: 'Hello World!'});
}

module.exports = socketApi;

应用程序.js

// Nothing here

通过这种方式socket.io,我可以从应用程序的任何地方调用一个module中的所有相关代码并从中调用。

这个答案值得更多赞!非常简单和干净,它将套接字路由保留在wwwapp.jsindex.js之外(是的,在index.js之外),这个文件应该只包含 Express HTTP 路由。
2021-03-18 04:13:20
与@tsujp 我的工作也一样。你必须点击正确的 url 并添加 socket.io 客户端,你会看到它工作
2021-03-19 04:13:20
任何人都可以为 socket.io 2.0 更新这个吗?它对我不起作用。io.attach(server) 和 io.listen(server) 都抛出“无法读取未定义的属性 X”。
2021-03-23 04:13:20
很棒,很干净
2021-04-03 04:13:20
我有一个与@tsujp 类似的问题,我正在使用 socket.io 2.3.0 并且我得到 io.attach is not a function
2021-04-12 04:13:20

事实证明,这确实是一些基本的语法问题......我从这个 socket.io 聊天教程中得到了这些台词......

在 ./bin/www 上,就在之后 var server = app.listen(.....)

var io = require('socket.io').listen(server);
require('../sockets/base')(io);

所以现在我创建 ../sockets/base.js 文件并将这个小家伙放在里面:

module.exports = function (io) { // io stuff here... io.on('conection..... }

是的!现在它可以工作了......所以我想我真的别无选择,只能在 /bin/www 中启动 socket.io ,因为那是我的 http 服务器启动的地方。目标是现在我可以在其他文件中构建套接字功能,保持module化,通过require('fileHere')(io);

<3

@Gofilord 那是因为它违背了套接字的全部目的……您需要的是常规路由,其中​​包括渲染。套接字只是在这里在没有 http 请求的情况下在客户端和服务器之间发送消息。也许阅读这篇文章enterprisewebbook.com/ch8_websockets.html
2021-03-20 04:13:20
问题是,你不能做这样的事情 io.on('connection', function(socket) { res.render('connection.jade') });
2021-03-31 04:13:20

旧的“expressjs”,一切都发生在“app.js”文件中。所以 socket.io 绑定到服务器也发生在那个文件中。(顺便说一句,仍然可以用旧的方式来做,并删除 bin/www)

现在使用新的 expressjs,它需要发生在“bin/www”文件中。

幸运的是,javascript/requirejs 使传递对象变得容易。正如 Gabriel Hautclocq 指出的那样,socket.io 仍然在“app.js”中“导入”,并通过属性附加到“app”对象

app.io = require('socket.io')();

socket.io 是通过将“bin/www”中的服务器附加到它来实现的

app.io.attach(server); 

因为“app”对象更早被传递到“bin/www”

app = require("../app");

真的很简单

require('socket.io')().attach(server);

但是以“困难”的方式执行此操作可确保app.io现在持有 socke.io 对象。

现在,如果您在“routes/index.js”中也需要这个 socket.io 对象,只需使用相同的原则来传递该对象。

首先在“app.js”中,做

app.use('/', require('./routes/index')(app.io));

然后在“路线/ index.js”

module.exports = function(io){
    //now you can use io.emit() in this file

    var router = express.Router();



    return router;
 }

所以“io”被注入到“index.js”中。

更新Gabriel Hautclocq的回复:

在 www 文件中,由于 Socket.io 的更新,代码应如下所示。附加现在是听。

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);


/**
 * Socket.io
 */
var io = app.io;
io.listen(server);`

此外,使该连接正常工作还需要实现客户端 API。这不是 Express 特定的,但没有它,connect 调用将无法工作。该 API 包含在

/node_modules/socket.io-client/socket.io.js. 

在前端包含此文件并使用以下内容进行测试:

var socket = io.connect('http://localhost:3000');