我目前正在 React/Express 中创建一个应用程序,并且正在学习如何创建会话。我正在使用快速会话,因为这是每个人都推荐的,但我有意想不到的行为。
在我的路线帖子中,连接期间使用的路线,我尝试为用户创建一个新会话,但它似乎不起作用(没有 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})
}
})
这是我如何设置快速会话以及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
。
您的
router.post("/login", ...)
路由永远不会向客户端发送任何响应。快速会话的工作原理是与浏览器建立 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/catch
和 throw
将更全面的错误处理集成到一个位置。
因此,由于某种原因,我的问题 Next.js 13(
app
目录)没有将我的 cookie 发送回 Express。我正在使用 express-session
和 cors
。我已经设法通过在标题上设置 Cookie
来修复。
关于 Next.js
router.ts
import {NextRequest, NextResponse} from "next/server";
export async function POST(request: NextRequest) {
// This will get all cookies value. You can use next/headers
// do get specific cookie key-value
const cookies = request.headers.get("cookie");
const req = await fetch("http://localhost:8080", {
method: "POST",
headers: {
// Make sure to include cookies in your request
// So your express-session is able to read connect.sid
Cookie: cookies!
},
// By default Next.js will cache your routes.
// For development purpose, if your API business
// logic, changes constantly, I suggest using "no-cache"
cache: "no-cache",
credentials: "include"
});
const resp = await req.json();
if (req.status === 200) {
return NextResponse.json({ message: "Success" }, { status: 200 });
} else {
return NextResponse.json({ message: "Internal Server Error", { status: 500 });
}
}