如果客户端在不同的域中,则快速会话不会持续存在
Express session doesn't persist if the client is on a different domain
tl:dr;
A Node (express) 服务器托管在 Heroku 上,UI 托管在 Netlify 上。当 UI 对服务器进行 REST API 调用时,会话不会持续存在(但如果我 运行 在本地,它会持续存在。localhost:5000
在服务器上,localhost:3000
on UI。UI 正在代理 package.json
) 的请求。
代码片段
session.ts
export const sessionConfig = {
secret: process.env.SESSION_KEY,
store: new RedisStore({ client: redisClient }),
resave: true,
saveUninitialized: true,
cookie: {
secure: process.env.NODE_ENV === 'production',
sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax',
},
};
server.ts
const app = express();
app.use(express.json());
app.use(cookieParser());
app.set('trust proxy', 1);
app.use(session(sessionConfig)); // This sessionConfig comes from the file above
app.use(cors({
credentials: true,
origin: process.env.CLIENT_URL,
}));
我用谷歌搜索了类似 express session not persist when cross domain request
的内容。然后,我看到了像 and this 这样的帖子。似乎 app.set('trust proxy', 1)
将确保为跨域请求保留会话数据。显然,就我而言,仍然缺少一些东西。
有人看到我做错了什么吗?任何建议将不胜感激!
PS:
我正在使用会话进行验证码测试,看起来像...
captch.ts
CaptchaRouter.get('/api/captcha', async (req: Request, res: Response) => {
const captcha = CaptchaService.createCaptcha();
req.session.captchaText = captcha.text;
res.send(captcha.data);
});
CaptchaRouter.post('/api/captcha', async (req: Request, res: Response) => {
if (req.session.captchaText !== req.body.captchaText) {
throw new BadRequestError('Wrong code was provided');
}
// The client sent the correct captcha
},
);
另一个PS:
以下是响应 heders 的样子:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.netlify.app
Connection: keep-alive
Content-Length: 46
Content-Type: application/json; charset=utf-8
Date: Sun, 09 Jan 2022 00:00:00 GMT
Etag: W/"2e-cds5jiaerjikllkslaxmalmird"
Server: Cowboy
Set-Cookie: connect.sid=s%3ramdon-string-here; Path=/; Expires=Sun, 09 Jan 2022 00:00:00 GMT; HttpOnly; Secure; SameSite=None
Vary: Origin
Via: 1.1 vegur
X-Powered-By: Express
原因是客户端(托管在 Netlify 上)没有代理 API 请求。
解决方案是:
- 在客户端
public
下添加_redirects
/api/* https://server.herokuapp.com/api/:splat 200
/* /index.html 200
- 确保来自客户端的 API 请求将以根 URL
开头
return axios({ method: 'POST', url: '/api/example', headers: defaultHeaders });
为了将来参考,这是我的会话配置
const sessionConfig = {
secret: process.env.SESSION_KEY || 'This fallback string is necessary for Typescript',
store: new RedisStore({ client: redisClient }),
resave: false,
saveUninitialized: true,
cookie: {
secure: process.env.NODE_ENV === 'production', // Prod is supposed to use https
sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax', // must be 'none' to enable cross-site delivery
httpOnly: true,
maxAge: 1000 * 60
} as { secure: boolean },
};
...这里是 server.ts
const app = express();
const port = process.env.PORT || 5000;
app.use(express.json());
app.set('trust proxy', 1);
app.use(session(sessionConfig));
app.use(cors({
credentials: true,
origin: process.env.CLIENT_URL,
}));
(正如@Matt Davis 指出的那样,cookieParser
是不必要的)
PS
我没有尝试在会话配置中设置 cookie.domain。如果这是设置给客户端 URL(由 Netlify 提供),会话 cookie 是否持续存在?
tl:dr;
A Node (express) 服务器托管在 Heroku 上,UI 托管在 Netlify 上。当 UI 对服务器进行 REST API 调用时,会话不会持续存在(但如果我 运行 在本地,它会持续存在。localhost:5000
在服务器上,localhost:3000
on UI。UI 正在代理 package.json
) 的请求。
代码片段
session.ts
export const sessionConfig = {
secret: process.env.SESSION_KEY,
store: new RedisStore({ client: redisClient }),
resave: true,
saveUninitialized: true,
cookie: {
secure: process.env.NODE_ENV === 'production',
sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax',
},
};
server.ts
const app = express();
app.use(express.json());
app.use(cookieParser());
app.set('trust proxy', 1);
app.use(session(sessionConfig)); // This sessionConfig comes from the file above
app.use(cors({
credentials: true,
origin: process.env.CLIENT_URL,
}));
我用谷歌搜索了类似 express session not persist when cross domain request
的内容。然后,我看到了像 app.set('trust proxy', 1)
将确保为跨域请求保留会话数据。显然,就我而言,仍然缺少一些东西。
有人看到我做错了什么吗?任何建议将不胜感激!
PS:
我正在使用会话进行验证码测试,看起来像...
captch.ts
CaptchaRouter.get('/api/captcha', async (req: Request, res: Response) => {
const captcha = CaptchaService.createCaptcha();
req.session.captchaText = captcha.text;
res.send(captcha.data);
});
CaptchaRouter.post('/api/captcha', async (req: Request, res: Response) => {
if (req.session.captchaText !== req.body.captchaText) {
throw new BadRequestError('Wrong code was provided');
}
// The client sent the correct captcha
},
);
另一个PS: 以下是响应 heders 的样子:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.netlify.app
Connection: keep-alive
Content-Length: 46
Content-Type: application/json; charset=utf-8
Date: Sun, 09 Jan 2022 00:00:00 GMT
Etag: W/"2e-cds5jiaerjikllkslaxmalmird"
Server: Cowboy
Set-Cookie: connect.sid=s%3ramdon-string-here; Path=/; Expires=Sun, 09 Jan 2022 00:00:00 GMT; HttpOnly; Secure; SameSite=None
Vary: Origin
Via: 1.1 vegur
X-Powered-By: Express
原因是客户端(托管在 Netlify 上)没有代理 API 请求。
解决方案是:
- 在客户端
public
下添加_redirects
/api/* https://server.herokuapp.com/api/:splat 200
/* /index.html 200
- 确保来自客户端的 API 请求将以根 URL 开头
return axios({ method: 'POST', url: '/api/example', headers: defaultHeaders });
为了将来参考,这是我的会话配置
const sessionConfig = {
secret: process.env.SESSION_KEY || 'This fallback string is necessary for Typescript',
store: new RedisStore({ client: redisClient }),
resave: false,
saveUninitialized: true,
cookie: {
secure: process.env.NODE_ENV === 'production', // Prod is supposed to use https
sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax', // must be 'none' to enable cross-site delivery
httpOnly: true,
maxAge: 1000 * 60
} as { secure: boolean },
};
...这里是 server.ts
const app = express();
const port = process.env.PORT || 5000;
app.use(express.json());
app.set('trust proxy', 1);
app.use(session(sessionConfig));
app.use(cors({
credentials: true,
origin: process.env.CLIENT_URL,
}));
(正如@Matt Davis 指出的那样,cookieParser
是不必要的)
PS
我没有尝试在会话配置中设置 cookie.domain。如果这是设置给客户端 URL(由 Netlify 提供),会话 cookie 是否持续存在?