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

Next.js 14对接外部后端:Token过期刷新失效问题及最佳实践咨询

Next.js 14 对接外部后端时 Token 过期拦截与处理问题及最佳实践

问题场景

当前架构为 Next.js 14 前端搭配独立 Node.js 后端,身份验证流程如下:

  • 初始从 Firebase Auth 客户端获取 Token 并传给后端,后端为 Next.js 客户端设置 Token Cookie
  • 通过 Server Actions 调用 API 时,从 next/headers 的 cookies 中获取 Token 随请求发送
  • Token 1 小时过期后,在 dashboard 路由的 error.tsx 中监听过期错误并尝试刷新 Token,但出现以下问题:
    开发者工具确认 Cookie 已更新为新 Token,但前端仍显示 Token 过期错误,API 返回 403 状态;仅多次页面导航后,Next.js 才更新恢复正常

现有代码展示

error.tsx 中的错误处理逻辑

useEffect(() => {
  if (error.message.includes('Firebase ID token has expired')) {
    getAuth()
      .currentUser?.getIdToken(true)
      .then(token => {
        refreshToken(token)
          .then(res => {
            if (res === 200) {
              router.refresh();
            }
          })
          .catch(error => console.log('Error refreshing token: ', error));
      });
  }
}, []);

refreshToken 函数代码

export const refreshToken = async (token: string) => {
  try {
    const response = await fetch(`${appConfig.BASE_URL}/create-session`, {
      method: 'POST',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    });

    if (!response.ok) {
      console.log("Couldn't refresh token");
    } else {
      revalidatePath('/dashboard');
      return response.status;
    }
  } catch (error) {
    console.log('refreshToken API call', error);
  }
};

问题原因分析

  1. useEffect 依赖缺失:当前依赖数组为空,无法感知 error 状态更新,导致错误信息变化时无法重新触发处理逻辑
  2. 页面刷新时机错误:router.refresh() 触发服务器组件重新渲染时,新 Cookie 可能未完全同步到请求上下文,服务器组件仍读取旧 Token 返回 403
  3. revalidatePath 调用无效:revalidatePath 是服务器端函数,在客户端环境调用不会生效,无法触发缓存重新验证

最佳实践方案

1. 修正客户端错误处理逻辑

  • 补充正确的 useEffect 依赖,确保错误状态变化时触发处理
  • 用 router.push 替代 router.refresh,强制刷新客户端与服务器请求上下文
  • 移除客户端无效的 revalidatePath 调用

修正后的 error.tsx 代码:

useEffect(() => {
  const handleTokenExpiry = async () => {
    if (error?.message.includes('Firebase ID token has expired')) {
      const auth = getAuth();
      if (!auth.currentUser) return;
      
      try {
        const newToken = await auth.currentUser.getIdToken(true);
        const res = await refreshToken(newToken);
        if (res === 200) {
          // 强制跳转当前路由,确保请求上下文同步新 Cookie
          await router.push('/dashboard');
        }
      } catch (err) {
        console.log('Token refresh failed:', err);
        // 刷新失败跳转登录页
        router.push('/login');
      }
    }
  };

  handleTokenExpiry();
}, [error, router]); // 添加error和router作为依赖

修正后的 refreshToken 函数:

export const refreshToken = async (token: string) => {
  try {
    const response = await fetch(`${appConfig.BASE_URL}/create-session`, {
      method: 'POST',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    });

    if (!response.ok) {
      console.log("Couldn't refresh token");
    }
    return response.status;
  } catch (error) {
    console.log('refreshToken API call', error);
    throw error; // 抛出错误让上层统一处理
  }
};

2. 服务器端统一拦截处理

在 Server Actions 中封装请求逻辑,主动检测 Token 过期并触发处理,避免依赖客户端被动错误捕获:

'use server';

import { cookies } from 'next/headers';

export async function fetchProtectedData() {
  const cookieStore = cookies();
  const token = cookieStore.get('auth-token')?.value;

  try {
    const res = await fetch(`${process.env.BASE_URL}/protected-endpoint`, {
      headers: { Authorization: `Bearer ${token}` },
      credentials: 'include',
    });

    // 检测后端返回的 Token 过期错误
    if (res.status === 403 && (await res.text()).includes('expired')) {
      throw new Error('Token expired');
    }

    return await res.json();
  } catch (err) {
    // 抛出错误让客户端组件捕获并触发刷新逻辑
    throw err;
  }
}

3. 全局错误拦截优化

在根布局或全局客户端组件中添加错误边界,统一处理 Token 过期场景,避免每个页面重复编写错误逻辑:

  • 使用 React ErrorBoundary 组件捕获全局组件错误
  • 监听全局请求错误,统一触发 Token 刷新流程

确保后端设置 Cookie 时配置正确的属性:

  • 设置 SameSite: 'lax' 或 'strict' 确保跨域请求时 Cookie 正常携带
  • 根据需求设置 HttpOnly(如果不需要客户端读取 Token)和 Secure 属性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:50:36