为什么我的“req.ession”不能创建一个会话?

p5fdfcr1  于 2022-10-21  发布在  iOS
关注(0)|答案(1)|浏览(155)

我目前正在使用Reaction/Express创建一个应用程序,并且正在学习如何创建会话。我使用Express-Session,因为这是每个人推荐的,但我有意想不到的行为。
在我的路由帖子(连接期间使用的路由)中,我尝试为用户创建一个新会话,但似乎不起作用(没有cookie,会话也没有创建),而我的console.log返回了预期的信息。

router.post('/login', async (req, res) => {
    const user = await Users.findOne({where: {Email: req.body.Email}})
    if (!user) res.json({error: "User doesn't exist"})
    bcrypt.compare(req.body.Password, user.Password).then((match) => {
        if (!match) res.json({error: "Wrong password"})
        req.session.user = user.dataValues
        console.log(req.session)
    })
})

在每次刷新页面时都会调用的get方法中,我意识到会话是空的,并且创建了一个新的cookie(我真的不知道为什么)。

router.get('/login', async  (req, res) => {
    console.log(req.session)
    if (req.session.user) {
        res.send({loggedIn: true, user: req.session.user})
    } else {
        res.send({ loggedIn: false})
    }
})

以下是我如何设置Express-Session和CORS(我读到问题可能来自那里,但似乎都是正确的)。

app.use(cors({
    origin: ["http://localhost:3000"],
    methods: ["GET", "POST"],
    credentials: true //permet d'activer les cookies
}))

app.use(session({
    key: "userId",
    secret: "foo",
    resave: false,
    saveUninitialised: true,
    cookie: {
        expires: 60 * 60 * 24
    },
}))

我还读到,问题可能来自API调用,我使用Axios,并且我小心地在调用之前添加了Axios.defaults.withCredentials = true行。

yfjy0ee7

yfjy0ee71#

您的router.post("/login", ...)路由永远不会将任何响应发送回客户端。Express会话的工作方式是与浏览器建立Cookie,浏览器将在将来的请求中发回该Cookie。该Cookie包含一个加密的会话密钥,它是使会话成为可能的魔法酱。如果您没有从/login post发送任何响应,则该cookie永远不会返回到浏览器,因此会话cookie不能在以后的请求中发送回,因此会话无法工作。
相反,来自浏览器的下一个请求将没有会话cookie,因此Express将尝试创建另一个新的空会话。
要修复该部分问题,请从您的POST请求发回一个响应:

router.post('/login', async (req, res) => {
    const user = await Users.findOne({where: {Email: req.body.Email}})
    if (!user) res.json({error: "User doesn't exist"})
    bcrypt.compare(req.body.Password, user.Password).then((match) => {
        if (!match) res.json({error: "Wrong password"})
        req.session.user = user.dataValues;
        console.log(req.session)
        res.send("some response");      // <== send some response here
    }).catch(err => {
        // some error handling here
        console.log(err);
        res.sendStatus(500);
    });
});

对于使用http状态反映实际错误的更完整和集中的错误处理,您可以这样做:

class myError extends Error {
    constructor(message, status) {
        super(message);
        this.status = status;
    }
}

router.post('/login', async (req, res) => {
    try {
        const user = await Users.findOne({where: {Email: req.body.Email}})
        if (!user) throw new MyError("User doesn't exist", 404) ;

        const match = await bcrypt.compare(req.body.Password, user.Password);
        if (!match) throw new MyError("Wrong password", 401);

        req.session.user = user.dataValues;
        console.log(req.session);
        res.json({loggedIn: true});
    } catch(e) {
        const status = e.status || 500;
        res.status(status).json({error: e.message});
    }
});

注意,我已经停止了await.then()的混合,这不被认为是好的风格,然后使用try/catchthrow将更全面的错误处理集成到一个点上。

相关问题