何时在express-session中使用saveUninitialized和resave?

96

我是使用MEAN技术栈的新手。我读了express-sessiongithub文档,但有些选项对我来说不太清楚。这些选项是saveUninitializedresave

请问有人可以用示例解释一下使用saveUninitializedresave的优点,如果我们改变这些选项中的布尔值,会产生什么影响。

语法:

app.use(session({
  resave: false,
  saveUninitialized: true,
}))
6个回答

211
假设会话已全局启用(适用于所有请求)。
当客户端发出HTTP请求并且该请求不包含会话cookie时,express-session将创建一个新的会话。创建新会话需要执行以下操作:
生成唯一的会话ID
将该会话ID存储在会话cookie中(以便可以识别客户端发送的后续请求)
创建空会话对象req.session
根据saveUninitialized的值,在请求结束时,会话对象将被存储在会话存储中(通常是某种类型的数据库)
如果在请求期间未修改会话对象,则在请求结束时并且saveUninitialized为false时,(仍为空的)会话对象将不会存储在会话存储中。
这样做的原因是防止将大量空会话对象存储在会话存储中。由于没有有用的信息可供存储,因此会话在请求结束时“被遗忘”。
何时应启用此功能?例如:当您要能够识别反复访问的访问者。您可以通过检查是否存在包含唯一ID的会话cookie来识别此类访问者。
关于resave:可能必须对不支持“touch”命令的会话存储进行启用。这告诉会话存储特定会话仍处于活动状态,这是必要的,因为一些存储将在一段时间后删除空闲(未使用)会话。
如果会话存储驱动程序不实现touch命令,则应启用resave,以便即使在请求期间未更改会话,它也仍在存储中进行更新(从而标记为活动状态)。
因此,是否需要启用此选项完全取决于您正在使用的会话存储。

1
@SurajJain,请通过robert AT klep DOT name给我发电子邮件 :D - robertklep
36
这是一个很棒的回答。感谢你抽出时间写下它。 - Gaston Sanchez
3
“touch”命令是什么?你所说的会话存储是在客户端还是服务器端? - nawK
1
Redis 需要重新保存吗? - R OMS
@ROMS 我不这么认为。 - robertklep
显示剩余5条评论

41

需要注意的一点是,如果您将 saveUninitialized 设置为 false,则会话cookie在会话未被修改时不会被设置到浏览器中。虽然这种行为可能是暗示的,但当我第一次阅读文档时并不清楚。


7
哇,这似乎帮了我很多。谢谢。我正在创建一个点赞按钮的POST请求,并将req.sessionID保存到数据库中。但是,每当我点击该按钮时,都会获得一个新的req.SessionID,真是可怕的一小时。不管怎样,当我为POST请求添加处理程序时,我添加了req.session.liked = id,现在我没有再获得新的会话ID了。希望这解决了我的问题。 - jack blank
但是如果'saveUninitialized'设置为"TRUE",但会话未被修改怎么办?我知道会话将保存在存储中,但会设置会话cookie吗? - Neel Patel

14

resave:它基本上意味着对于发送到服务器的每个请求,它都会重置会话cookie。即使请求来自同一用户或浏览器,并且在请求期间未修改会话。

saveUninitialized:当创建一个空会话对象并且没有设置任何属性时,它处于未初始化状态。因此,将saveUninitialized设置为false,如果会话未被修改,则不会保存会话。

resavesaveUninitialized的默认值均为true,但使用默认值已被弃用。因此,请根据具体情况设置适当的值。


6
  1. Uninitialised = false
    它意味着当 req.session 中的任何属性被修改时,您的会话仅存储在您的存储中。
  2. Uninitialised = true
    它意味着每次请求时都会将您的会话存储到存储器中,而不依赖于 req.session 的修改。
  3. resave = true
    当对会话进行修改时,它表示会重写 req.session.cookie 对象。
  4. resave = false
    它不会重写 req.session.cookie 对象。初始的 req.session.cookie 保持不变。

2
我得出了一个结论:
1. 当你将saveUninitialized设置为false时,如果你创建的会话对象没有被修改即为空,那么你在浏览器cookie中将看不到connect.sid。这最终会导致你的存储不存储会话对象,因为它没有被修改即未初始化。反之亦然,当saveUninitialized设置为true时,情况相反。
例如:
const express = require('express');
const dotenv = require("dotenv").config();
const app = express();
const session = require("express-session");
app.use(session({
  secret:"cat",
  resave:false,
  saveUninitialized:false,
  cookie:{httpOnly:true}
}));
app.get('/login',(req,res)=>{
  // req.session.user="sundar";
  // req.session.admin=true;
  console.log(req.sessionID);
  res.send(req.session.user);
})

app.post("/upload",(req,res)=>{
  console.log(req.session);
  if (req.session.user === "sundar") {
    res.send("uploaded" + req.session.user)
  }else{
    res.send("failed");
  }
  
})

app.listen(process.env.PORT, () => {
  console.log(`Listening on http://localhost:${process.env.PORT}`);
});

在这个例子中,如果您在postman或浏览器中输入“/login”,并查看cookies,您将无法看到connect.id,因为创建的会话对象未被修改。
但是,如果您将“/login”修改为:
app.get('/login',(req,res)=>{
   req.session.user="sundar";
   req.session.admin=true;
/* here we modified session object by adding user and admin properties to object created */
  res.send(req.session.user);
})

因此,您可以看到connect.id cookie在浏览器或postman cookies部分被设置。这也意味着,如果您的会话中间件连接了存储,那么您的会话现在将存储在存储中。

  1. 如果将resave设置为true,则每次请求时都会重置会话cookie。参考:点击此处阅读

只要其他人知道,你不必说res.send(req.session.user),只需像平常一样发送你的res.send,只需简单地更改req.session.variable就足以触发更改。 - Joseph Astrahan

0

当saveUninitialized设置为true时,服务器将向浏览器提供会话cookie并将其保存在内存中,即使您没有对会话对象进行任何修改。但是,当后面的字段设置为false时,只有在您修改会话对象时,服务器才会提供会话cookie。如果您已经拥有会话cookie,则无需担心!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接