如何确保JWT Cookie设置完成后再使用?(Next.js+NestJS场景)
问题场景
使用Next.js + NestJS实现JWT授权码流程:
- 前端拿到OAuth服务器返回的授权码后,调用后端
/auth/42/callback接口 - 后端验证授权码后生成JWT,通过响应头设置
jwtCookie - 浏览器能成功写入Cookie,但前端读取时频繁出现
jwt为undefined的情况,排查发现是Cookie写入与响应返回存在时序差,导致读取时机过早
相关代码
前端请求代码
const response = await fetch( 'http://localhost:4000/auth/42/callback?code=' + code, { // code 来自OAuth服务器 method: 'POST', mode: 'cors', headers: { 'Content-Type': 'application/json', }, credentials: 'include', } );
后端回调接口代码
@Post('42/callback') async Callback(@Query('code') code: string, @Res({passthrough: true}) res) { if (!code) { res.status(400).send('Missing code'); return; } try { const response = await this.authService.exchangeCodeForToken(code); const jwt = await this.authService.handleCallback(response); res.setHeader('Access-Control-Allow-Credentials', 'true'); res.cookie('jwt', jwt, { sameSite: 'strict' }); res.status(200).send(); } catch (error) { console.error(error); res.status(500).send('Internal server error'); } }
前端读取Cookie代码
import jwtDecode from 'jwt-decode'; import { useCookies } from 'react-cookie'; const [ cookies ] = useCookies(); const jwt = cookies.jwt; const jwtPayload: any = jwtDecode(jwt); // jwt 此处为undefined
解决方法
1. 等待请求完成后主动读取Cookie
组件初始化时的cookies对象是静态的,不会自动更新。必须在fetch请求完成后,主动获取最新的Cookie值:
// 修正后的请求及读取逻辑 const handleCallback = async (code) => { const response = await fetch( 'http://localhost:4000/auth/42/callback?code=' + code, { method: 'POST', mode: 'cors', headers: { 'Content-Type': 'application/json', }, credentials: 'include', } ); if (response.ok) { // 请求完成后主动获取最新Cookie const { getCookie } = useCookies(); const jwt = getCookie('jwt'); if (jwt) { const jwtPayload = jwtDecode(jwt); // 执行后续业务逻辑 } } };
2. 监听Cookie变化
利用react-cookie的状态监听能力,当jwt Cookie更新时自动触发逻辑:
import { useCookies, CookieProvider } from 'react-cookie'; import jwtDecode from 'jwt-decode'; import { useEffect } from 'react'; function AuthCallback() { const [cookies] = useCookies(['jwt']); useEffect(() => { // 当jwt Cookie存在时处理解码逻辑 if (cookies.jwt) { const jwtPayload = jwtDecode(cookies.jwt); // 比如跳转到主页、存储用户信息等 } }, [cookies.jwt]); // 监听jwt Cookie的变化 // 发起回调请求的逻辑 const fetchCallback = async (code) => { await fetch('http://localhost:4000/auth/42/callback?code=' + code, { method: 'POST', mode: 'cors', headers: { 'Content-Type': 'application/json' }, credentials: 'include', }); }; return <div>{/* 组件内容 */}</div>; } // 必须在外层包裹CookieProvider export default function App() { return ( <CookieProvider> <AuthCallback /> </CookieProvider> ); }
3. 完善后端Cookie配置
确保Cookie的作用域和属性配置正确,避免写入异常:
res.cookie('jwt', jwt, { sameSite: 'strict', path: '/', // 显式指定作用域为根路径 secure: process.env.NODE_ENV === 'production', // 生产环境HTTPS下开启 httpOnly: false, // 需要前端读取时必须设为false,否则仅后端可读取 maxAge: 3600 * 1000, // 可选:设置Cookie有效期,单位毫秒 });
4. Next.js客户端组件特殊处理
如果是Next.js客户端组件,也可以手动解析document.cookie,但需保证在请求完成后执行:
const getCookie = (name) => { return document.cookie.split('; ').find(item => item.startsWith(`${name}=`))?.split('=')[1]; }; // 请求完成后读取 const response = await fetch(...); if (response.ok) { // 极端情况可加微小延迟确保Cookie写入(不推荐依赖,优先用监听方式) const jwt = getCookie('jwt'); if (jwt) { const payload = jwtDecode(jwt); } }
内容的提问来源于stack exchange,提问作者Théo Vogel
相关产品推荐
相关产品推荐

