使用 node.js / express-session 是否可以在会话中仅保存一个 属性?

With node.js / express-session is it possible to save() just one property on the session?

环境: Node.js,Express,express-session

问题:是否可以只保存一个 属性 会话而不是保存整个会话?

背景:通常express-session在每个http响应结束时保存会话,即路由完成时。但是,可以随时使用 req.session.save() 保存会话。这将保存整个会话。通常这不是问题,但我有一个用例,这是一个问题。

解释: 在下面的代码中,我将 req 传递给 subfunction。此函数更改会话中的 属性,然后使用 req.session.save() 保存会话。不幸的是,当我将 req 传递给 subfunction 时,req.session.myProperty 被设置为 true。当我保存会话时,如果在主路由中 属性 已经更改为 false,它会存储 true。在 subfunction 中,我需要做的是更新 req.session.someOtherProperty,然后只保存那个 属性。这可能吗?

示例:

function myRoute(req, res) {
  
    req.session.myProperty = true;

    subFunction(req);  // runs in the background while the route continues.

    req.session.myProperty = false;    

    // do more stuff and return

}

function async subFunction(req) {

    // uh oh, req.session.myProperty was passed in as true.
    // In the main route it's already been changed to false.

    let testURLResult = await testIfURLActive('www.example.com'); 

    req.session.testURLResult = testURLResult;
    req.session.save(); // I need it to save just req.session.testURLResult, not the entire session.

    // req.session.myProperty was just saved as true because that's what passed in.  When I save it overwrites the false value that was set in the main route.

    return;

}

好的,所以我想我终于明白问题是你有一个异步操作可能需要一段时间才能 运行 完成后你想保存一个特定的 属性 在会话中,以便它在未来的请求中持续存在。

但是,如果您使用现有的 req.session 对象,更新那个 属性 并对其调用 req.session.save(),您将保存一个可能覆盖其他对象的陈旧会话对象在这个 运行ning 长请求 运行ning.

期间被其他请求合法更改的属性

我能想到的两种方法来保存你的新 属性 是:

  1. 直接访问会话存储并更新会话存储中的 属性。

  2. 让 express-session 给你一个新的、更新的 req.session,修改你的 属性,然后在那个新更新的会话上调用 req.session.save()对象。

由于您没有显示任何关于您使用的会话存储类型的信息,因此我将在此处重点介绍第二个选项。您可以通过删除当前的 req.session 并再次调用会话中间件来做到这一点,这实际上会获取一个新的 fresh 副本会话。

你没有显示你的会话初始化代码,但让我们从文档中举一个例子:

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}));

所以,首先将其更改为:

const sessionMiddleware = session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
});
app.use(sessionMiddleware);

我们需要保存会话中间件的副本,以便稍后手动调用它。

然后,在你的长 运行ning 函数中,你可以像这样使用它:

// note I am passing res and next here now too
async function subFunction(req, res, next) {
    let testURLResult = await testIfURLActive('www.example.com'); 

    // remove the current session object from req to we can obtain a fresh one
    delete req.session;
    // repopulate req.session
    sessionMiddleware(res, req, err => {
        if (err) {
            next(err);
            return;
        }
        // fresh req.session here
        req.session.testURLResult = testURLResult;
        req.session.save();        
    });
}

请注意,这里还有其他问题需要解决:

  1. 您没有针对 testIfURLActive() 或调用 subFunction() 的错误处理。如果任何一个都可以拒绝,那么您将遇到一个未处理的拒绝,这将终止您在最新版本 node.js 中的服务器。你需要在那里捕捉拒绝,除非那永远不会拒绝。

  2. 因为修改后的subFunction()需要能够充当full-blown中间件,所以我现在将req, res, next传递给它。您将需要修改调用它的位置。