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

如何确保Fetch请求前Cookie已就绪?解决首次渲染数据获取失败问题

解决方案

方法一:合并请求逻辑,确保Cookie设置后再获取数据

把获取令牌和数据的逻辑放在同一个useEffect里,通过链式调用让数据请求等待Cookie设置完成后再执行:

import Cookies from 'js-cookie';    
const [isLoading, setLoading] = useState(false)
const [data, setData] = useState(null)

useEffect(() => {
  setLoading(true)
  fetch('/api/token')
    .then((res) => res.json())
    .then((tokenData) => {
      Cookies.set("TOKEN", tokenData.access_token);
      // 令牌写入Cookie后立刻发起数据请求
      return fetch('/api/data');
    })
    .then((res) => res.json())
    .then((data) => {
      setData(data);
      setLoading(false);
    })
    .catch((err) => {
      // 请求失败时重置加载状态
      setLoading(false);
      console.error('请求出错:', err);
    });
}, [])

方法二:用状态变量跟踪令牌状态,触发数据获取

新增一个状态变量标记令牌是否设置完成,数据请求的useEffect依赖这个状态,只有当令牌就绪后才执行:

import Cookies from 'js-cookie';    
const [isLoading, setLoading] = useState(false)
const [data, setData] = useState(null)
const [tokenReady, setTokenReady] = useState(false);

// 专门负责获取并设置令牌
useEffect(() => {
  fetch('/api/token')
    .then((res) => res.json())
    .then((tokenData) => {
      Cookies.set("TOKEN", tokenData.access_token);
      setTokenReady(true); // 标记令牌已写入Cookie
    })
    .catch((err) => {
      console.error('获取令牌失败:', err);
    });
}, [])

// 令牌就绪后才请求数据
useEffect(() => {
  if (!tokenReady) return;

  setLoading(true)
  fetch('/api/data')
    .then((res) => res.json())
    .then((data) => {
      setData(data);
      setLoading(false);
    })
    .catch((err) => {
      setLoading(false);
      console.error('获取数据失败:', err);
    });
}, [tokenReady])

方法三:跳过Cookie,直接传递令牌(可选优化)

如果不需要把令牌持久化到客户端Cookie,可直接在获取令牌后通过请求头传给数据接口,彻底避开Cookie的时机问题:

const [isLoading, setLoading] = useState(false)
const [data, setData] = useState(null)

useEffect(() => {
  setLoading(true)
  fetch('/api/token')
    .then((res) => res.json())
    .then((tokenData) => {
      // 直接把令牌通过请求头传给数据接口
      return fetch('/api/data', {
        headers: {
          'Authorization': `Bearer ${tokenData.access_token}`
        }
      });
    })
    .then((res) => res.json())
    .then((data) => {
      setData(data);
      setLoading(false);
    })
    .catch((err) => {
      setLoading(false);
      console.error('请求出错:', err);
    });
}, [])

同时修改/api/data.js,优先从请求头读取令牌:

export default async function handler(req, res) {
  // 先从请求头取令牌,没有再读Cookie
  const authHeader = req.headers.authorization;
  const token = authHeader ? authHeader.split(' ')[1] : req.cookies['TOKEN'];

  if (token){
    const result = await fetch(`url`, {
      headers: {
        accept: 'application/json',
        Authorization: `Bearer ${token}`,
      }
    });
    const data = await result.json()
    res.status(200).json(data)
  } else {
    res.status(401).json({ message: '未提供访问令牌' });
  }
}

额外提示

  • 所有请求都要加错误处理,避免加载状态一直卡在true;
  • 如果需要持久化令牌,设置Cookie时可以加上过期时间:Cookies.set("TOKEN", tokenData.access_token, { expires: 7 }),这样下次访问时Cookie已存在,不会再出现首次加载问题。

内容的提问来源于stack exchange,提问作者greendalf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:40:29