灵感来自如何与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和许多其他请求信息。因此,服务器可以通过套接字访问该初始请求。request.
我的第一个问题是,为什么握手请求不在express会话中间件的范围内?(更普遍地说,在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
导致应用程序崩溃,可以通过提供空对象而不是套接字.request.res来解决问题,比如:sessionMiddleware(socket.request, {}, next);
,在我看来这是一个肮脏的黑客。socket.request.res屈服于undefined
的原因是什么?
尽管@oLeduc有点正确,但还有一些事情需要解释。。
为什么握手的请求不在express会话中间件的范围内
这里最大的原因是express中的中间件是为处理特定于请求的任务而设计的。不是所有的,但大多数处理程序都使用标准的req, res, next
语法。如果我可以说的话,套接字是"无请求"的。事实上,您拥有socket.request
是由于握手的方式,并且它使用HTTP进行握手。所以socket.io的人把第一个请求入侵到了你的socket类中,这样你就可以使用它了。它不是由express团队设计的,用来处理套接字和TCP。
使用io.use((定义的中间件将在哪些场景中启动
CCD_ 15是CCD_。在express中,中间件是在每个请求上执行的,对吧?但是套接字没有请求,在每个套接字发射上使用中间件会很困难,所以它们让它在每个连接上执行。但是,除了在处理(和响应(实际请求之前堆叠和使用express中间件外,Socket.IO在连接时甚至在实际握手之前使用中间件!如果你愿意,你可以使用这种中间件来拦截握手,这非常方便(为了保护你的服务器免受垃圾邮件的攻击(。更多信息可以在护照插槽的代码中找到
为什么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是如何实现的——你可以在这里阅读更多。它连接到常规服务器,并发送请求以进行握手。我只能想象,有时在出现错误时,标头会与响应分离,这就是为什么你不会得到任何响应的原因。无论如何,仍然只是猜测。
希望信息能有所帮助。
为什么握手的请求不在express会话中间件的范围内
因为socket.io将附加到http。服务器,它是express下的层。在socket.io.的来源中的一条评论中提到了这一点
原因是第一个请求是一个常规的http请求,用于将请求的无状态http连接升级为状态完整的websocket连接。因此,它必须经历适用于常规http请求的所有逻辑,这没有多大意义。
使用io.use((定义的中间件将在哪些场景中启动
每当创建新的套接字连接时。
因此,每当客户端连接时,它都会调用使用io.use((注册的中间件。然而,一旦客户端连接,当从客户端接收到数据包时,它就不会被调用。无论连接是在自定义名称空间还是在主名称空间上启动,它都将被调用。
为什么io.use((在io.of('/abc'(.use((之前触发
名称空间是socket.io实现的一个细节,实际上,websocket总是首先到达主名称空间。
为了说明这种情况,请查看这个片段及其产生的输出:
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未定义
据我所知,它永远不应该被定义。它可能与您的具体实现有关。