无法从带有 Socket.IO 的 cookie 中获取 Express 会话 ID

Posted

技术标签:

【中文标题】无法从带有 Socket.IO 的 cookie 中获取 Express 会话 ID【英文标题】:Can't get Express session ID from cookies w/ Socket.IO 【发布时间】:2012-05-08 17:10:06 【问题描述】:

我在 Node 中有一个典型的 Web 应用程序,它使用 Express 框架和会话中间件。我还将 Socket.io 用于我的应用程序的某些动态部分(目前,这是一种聊天机制,但这是切线的)。我已经能够成功地自行设置会话和 socket.io,但希望将它们结合起来(例如:将套接字聊天消息与用户帐户相关联而无需访问数据库)。

应该注意(我可以看到这是一个可能的问题点),我在不同的端口上运行两台快速服务器:一台用于常规 HTTP 流量,另一台用于 HTTPS 流量。但是,我让两台服务器都进行了相同的配置并共享相同的会话存储。会话确实在 http 和 https 页面之间持续存在。会话最初是通过 HTTPS 提供的页面设置的,而 socket.io 页面是普通 HTTP。

我正在遵循位于 here 的指南来实现我正在寻找的关于集成 socket.io 和会话的内容。但是,在授权函数中,从未设置 data.headers.cookie,尽管我的应用程序的基于会话的部分按预期工作。更奇怪的是,在设置会话后,如果我在浏览器中执行console.log(document.cookie),我会得到一个空字符串,但是当我使用 Firefox 开发人员工具栏查看我的 cookie 时,有一个用于 express 和连接。

这是服务器代码的相关部分:

var config = 
    ip          : "127.0.0.1",
    httpPort    : 2031,
    httpsPort   : 2032
;

var utils       = require("./utils"),
    express     = require('express'),
    fs          = require('fs'),
    parseCookie = require('./node_modules/express/node_modules/connect').utils.parseCookie,
    routes      = require('./routes')(config); 

var httpsOpts = 
    key : fs.readFileSync("cert/server-key.pem").toString(),
    cert: fs.readFileSync("cert/server-cert.pem").toString()
 ;

var app             = express.createServer(),
    https           = express.createServer(httpsOpts),
    io              = require("socket.io").listen(app,  log: false),
    helpers         = require("./helpers.js"),
    session         = new express.session.MemoryStore(),
    sessionConfig   = express.session(
        store   : session,
        secret  : 'secret',
        key     : 'express.sid',
        cookie  : maxAge : 60 * 60 * 1000
    ); //share this across http and https

configServer(app);
configServer(https);

//get SID for using sessions with sockets
io.set('authorization', function(data, accept)
    if(data.headers.cookie)
        data.cookie = parseCookie(data.headers.cookie);
        data.sessionID = data.cookie['express.sid'];
     else 
        return accept("No cookie transmitted", false);
    

    accept(null, true);
);

io.sockets.on('connection', function(socket)
    //pull out session information in here
);

function configServer(server) 
    server.configure(function()
        server.dynamicHelpers(helpers.dynamicHelpers);
        server.helpers(helpers.staticHelpers);
        server.set('view options',  layout: false );
        server.set('view engine', 'mustache');
        server.set('views', __dirname + '/views');
        server.register(".mustache", require('stache'));
        server.use(express.static(__dirname + '/public'));
        server.use(express.bodyParser());
        server.use(express.cookieParser());
        server.use(sessionConfig);
    );

这是客户端上的相关代码:

<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
    $(document).ready(function()
        var socket = io.connect('http://127.0.0.1'); //make sure this isn't localhost!
        socket.on('server', function(data)
            //socket logic is here
        );
    
</script>

更新

即使在使用 SocketIO 的页面的路由中手动设置了 cookie(而不仅仅是会话变量),请求的 cookie 部分仍然不存在。

【问题讨论】:

【参考方案1】:

在被告知查看客户端的初始化之前,我永远不会想到这一点。我将地址从 localhost 更改为显式 IP (127.0.0.1),cookie 现在与 Socket.IO 中的标头一起发送。我不确定这是否明显,因为我假设 localhost 无论如何都被映射到 127.0.0.1。

【讨论】:

没错!这就是我想要客户端代码的原因。您也可以使用var socket = io.connect(); 而不提供主机。应该工作。 是的,正如@freakish 提到的,始终使用最小连接客户端代码:var socket = io.connect()

以上是关于无法从带有 Socket.IO 的 cookie 中获取 Express 会话 ID的主要内容,如果未能解决你的问题,请参考以下文章

我可以从 Socket.io 访问 cookie 吗?

如何从服务器向 socket.io 客户端发送 cookie?

带有 socket.io 和 express 的 Websocket

无法接收通知 - 带有 Socket.io 的 Laravel

尝试发出时,带有 Node.js 的 Socket.io 在路由文件中返回未定义

带有express和socket.io的节点js-找不到socket.io.js