受到如何与Socket.IO 1.x和Express 4.x共享会话的启发,我以某种“干净”的方式实现了套接字认证,无需使用cookie解析器并从头文件中读取cookie,但很少有项目对我来说仍不清楚。示例使用上一个稳定的socket.io版本1.3.6。
var express = require('express'),
session = require('express-session'),
RedisStore = require('connect-redis')(session),
sessionStore = new RedisStore(),
io = require('socket.io').listen(server);
var sessionMiddleware = session({
store : sessionStore,
secret : "blabla",
cookie : { ... }
});
function socketAuthentication(socket, next) {
var sessionID = socket.request.sessionID;
sessionStore.get(sessionID, function(err, session) {
if(err) { return next(err); }
if(typeof session === "undefined") {
return next( new Error('Session cannot be found') );
}
console.log('Socket authenticated successfully');
next();
});
}
io.of('/abc').use(socketAuthentication).on('connection', function(socket) {
// setup events and stuff
});
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.get('/', function(req, res) { res.render('index'); });
server.listen(8080);
index.html
<body>
...
<script src="socket.io/socket.io.js"></script>
<script>
var socket = io('http://localhost:8080/abc');
</script>
</body>
所以io('http://localhost:8080/abc');
从客户端发送初始HTTP握手请求到服务器,从服务器可以收集cookie和许多其他请求信息。所以服务器可以通过socket.request访问该初始请求。
我的第一个问题是为什么握手请求不在快速会话中间件的范围之内?(更普遍地在app.use
中间件范围内?)在某种程度上,我预计这个app.use(sessionMiddleware); 在该初始请求之前触发,然后轻松访问socket.request.session
其次,中间件定义的场景io.use()
会发生什么?仅用于初始HTTP握手请求?它似乎io.use()
是用于套接字相关的东西(问题是:什么东西),而app.use
标准的请求。
我不太清楚为什么在上面的例子中io.use()
被解雇了io.of('/abc').use()
。我故意写下这个命令,io.of('/abc').use()
首先看它是否会起作用,并且工作正常。应该反过来写。
最后,socket.request.res也像一些人在链接问题中指出的,有时会undefined
导致应用程序崩溃,问题可以通过提供空对象而不是socket.request.res来解决
发布于 2018-04-26 15:39:27
尽管@oLeduc是正确的,但还有几件事要解释..
为什么握手请求不在快速会话中间件的范围内?
这里最大的原因是express中的中间件被设计为处理特定于请求的任务。不是全部,但大多数处理程序使用标准req, res, next
语法。如果我能说,套接字是“无需请求”的。你拥有的事实socket.request
是由于握手的方式,并且它使用HTTP。所以socket.io中的这些人首先要求进入你的套接字类,以便你可以使用它。它不是由快速团队设计的,以便与套接字和TCP一起工作。
使用io.use()定义的中间件会触发哪些场景?
io.use
是表达use
中间件方式的一种紧密表示。在快递中,中间件在每个请求上执行,对吧?但是套接字没有请求,并且在每个套接字上使用中间件会很尴尬,因此它们已经在每个连接上执行它。但是,除了在实际请求被处理(和响应)之前堆叠和使用快速中间件,Socket.IO使用中间件进行连接,甚至在实际握手之前!如果你想使用那种非常方便的中间件(为了保护你的服务器免受垃圾邮件攻击),你可以拦截握手。更多信息可以在passport-socketio的代码中找到
为什么io.use()在io.of('/ abc')。use()之前触发?
关于这个的真正解释可以在这里找到,这是这个代码:
Server.prototype.of = function(name, fn){
if (String(name)[0] !== '/') name = '/' + name;
if (!this.nsps[name]) {
debug('initializing namespace %s', name);
var nsp = new Namespace(this, name);
this.nsps[name] = nsp;
}
if (fn) this.nsps[name].on('connect', fn);
return this.nsps[name];
};
在代码的开头,有这样一行代码:
this.sockets = this.of('/');
所以,在一开始就有一个默认的命名空间。就在那里,你可以看到它立即有一个connect
听众附着在它上面。之后,每个命名空间都会得到完全相同的connect
侦听器,但是因为Namespace
是EventEmitter
,侦听器会一个接一个地添加,所以它们会一个接一个地触发。换句话说,默认名称空间首先是侦听器,所以它首先触发。
我不认为这是故意设计的,但恰巧是这样:)
为什么socket.request.res未定义?
说实话,我对此并不确定。这是因为engine.io的实现方式 - 您可以在这里阅读更多内容。它连接到常规服务器,并发送请求以进行握手。我只能想象,有时出错时头部与响应分开,这就是为什么你不会得到任何答案。无论如何,仍然只是猜测。
希望信息有帮助。
发布于 2018-04-26 16:52:00
为什么握手请求不在快速会话中间件的范围内?
因为socket.io将附加到一个http.Server,它是快速下的图层。它在socket.io 的源代码中的评论中提到。
这是因为第一个请求是一个常规的http请求,用于将请求的无状态http连接升级为完全状态的websocket连接。因此,它必须通过适用于常规http请求的所有逻辑,这没什么意义。
使用io.use()定义的中间件会触发哪些场景?
每当创建一个新的套接字连接时。
所以每次客户端连接时都会调用使用io.use()注册的中间件。然而,一旦客户端连接上了,当从客户端接收到数据包时它就不会被调用。如果连接是在自定义命名空间或主命名空间上启动的,则无关紧要,它将始终被调用。
为什么io.use()在io.of('/ abc')。use()之前触发?
命名空间是socket.io实现的一个细节,事实上,websockets将始终首先命中主命名空间。
为了说明这种情况,请看这段代码和它产生的输出:
var customeNamespace = io.of('/abc');
customeNamespace.use(function(socket, next){
console.log('Use -> /abc');
return next();
});
io.of('/abc').on('connection', function (socket) {
console.log('Connected to namespace!')
});
io.use(function(socket, next){
console.log('Use -> /');
return next();
});
io.on('connection', function (socket) {
console.log('Connected to namespace!')
});
输出:
Use -> /
Main namespace
Use -> /abc
Connected to namespace!
查看socket.io团队添加到他们的文档中的警告:
重要说明:命名空间是Socket.IO协议的实现细节,并且与底层传输的实际URL无关,默认为/socket.io/...。
为什么socket.request.res未定义?
据我所知,它永远不应该是未定义的。这可能与您的具体实施有关。
https://stackoverflow.com/questions/-100008269
复制相似问题