我正在开发一个具有 Express.js 后端和 Next.js 前端的应用程序。我的后端使用
Redis
和 connect-redis
包进行会话管理,我的服务器部署在带有 Heroku-Data for Redis
插件的 Heroku 上。
我遇到一个问题,尽管配置了 CORS 标头以接受凭据,但会话 cookie 并未在跨源上下文中从服务器发送到前端。
以下是我的服务器端 (Express.js) 配置的摘录:
// app.js
...
// initialize Redis
async function initializeRedis() {
const redisClient = redis.createClient({
url: process.env.REDIS_TLS_URL, // url provided by Heroku-Data for Redis
socket: {
tls: true,
rejectUnauthorized: false,
},
});
redisClient.on("error", function (error) {
console.error("Erreur de Redis :", error);
});
await redisClient.connect().catch(console.error);
return redisClient;
}
// start app
async function startApp() {
/* Redis
-------------------------------------------------- */
const redisClient = await initializeRedis();
const redisStore = new RedisStore({ client: redisClient });
/* Express Session
-------------------------------------------------- */
const sessionConfig = {
store: redisStore,
secret: process.env.EXPRESS_SESSION_SECRET_KEY,
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 600000, // 10 minutes
secure: process.env.NODE_ENV === "production",
httpOnly: true,
sameSite: process.env.NODE_ENV === "production" ? "None" : "Strict",
},
};
/* CORS
-------------------------------------------------- */
const cors = require("cors");
const corsOptions = {
origin: "https://www.my-site.app",
methods: ["GET", "POST"],
allowedHeaders: ["Content-Type", "Authorization"],
credentials: true,
};
...
}
这是我在客户端(Next.js)发出请求的方式:
// this request creates the session in the backend, storing the order id in the session cookie
const response = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_ENDPOINT}/validate-order`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(order),
credentials: "include",
}
);
// this request is supposed to receive the cookie from the session
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_ENDPOINT}/get-order-id`,
{
method: "GET",
credentials: "include",
}
);
向我的 API 发出请求时,客户端不会收到会话 cookie(我的前端通过 https 部署到 Vercel)。响应标头中没有 cookie。我已经检查过,并且确信该问题与 CORS 配置无关,因为适当的标头似乎已就位,并且确实允许跨源请求。
有人遇到过这个问题或者知道可能出了什么问题吗?我可能缺少 Heroku 或 Redis 配置的某些特定内容吗?
预先感谢您的帮助。
我尝试过的:
当我查看 Redis 数据库时,我可以看到密钥已正确创建并且不为空:
sess:e22dFw38IpASoyv3Hk-xxx
我注意到我可以通过 Express-Session cookie 的此配置正确接收 cookie :
secure : false,
sameSite : « Strict »
但仅当请求来自 http://localhost:3000 并且服务器在本地运行时。当服务器使用此配置在 Heroku 上运行时,我没有收到 cookie。
我将
maxAge
cookie 参数更新为 2 小时,以确保问题与时区无关
将我的服务器部署在自定义域上,并启用 Heroku SSL,如此线程中所述。前端仍然没有 cookie。
将
domain
参数添加到 app.js
中的 cookie 配置中,如此处所述:
const sessionConfig = {
...
cookie: {
...
domain: ".my-site.app", // do this only if your server and your front-end share the same domain, with your server on a subdomain like api.my-site.app
},
};
通过将
app.set("trust proxy", 1);
添加到服务器(如此处所述)来解决问题。
像 Heroku 这样的云服务经常使用反向代理,因此这一行告诉 Express 初始请求是通过 https 发出的,即使它是在代理之后通过 http 传输的。