You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确保JWT Cookie设置完成后再使用?(Next.js+NestJS场景)

授权码流程中Cookie读取时机问题的解决方案

问题场景

使用Next.js + NestJS实现JWT授权码流程:

  1. 前端拿到OAuth服务器返回的授权码后,调用后端/auth/42/callback接口
  2. 后端验证授权码后生成JWT,通过响应头设置jwt Cookie
  3. 浏览器能成功写入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 05:13:15