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

Next.js14 App Router服务端Axios设置Cookie解决方案求助

Next.js 14 App Router 服务端Axios拦截器更新Cookie方案

问题背景

使用Next.js14 App Router + Axios构建项目,在服务端Axios拦截器中处理AccessToken过期逻辑:捕获401错误后通过RefreshToken获取新AccessToken,但Next.js14限制仅能在Server Action或路由处理器中修改Cookie,直接在拦截器中调用cookies().set()无效。尝试过重定向调用Server Action触发NEXT_REDIRECT错误,使用cookies-next库也未解决,希望保留服务端请求优势,不切换到页面路由或客户端Axios。

现有拦截器代码

instance.interceptors.response.use(
  (config) => config,
  async (error) => {
    //토큰 만료 에러
    if (error.response.status === 401) {
      const newAccessToken = await getNewAccessToken();

      if (newAccessToken) {
        error.config.headers.Authorization = `Bearer ${newAccessToken}`;
        cookies().set("accessToken", newAccessToken);
        return axios(error.config);
      } else {
        // logout
      }
    }

    return Promise.reject(error);
  },
);

解决方案

核心思路是将刷新Token+设置Cookie的逻辑封装到Server Action中,服务端Axios拦截器直接调用该Action完成操作,避免在拦截器中直接操作Cookie。

1. 封装刷新Token的Server Action

在app/actions/auth.actions.ts(或对应路径)中创建Server Action,统一处理Token刷新和Cookie设置:

'use server';

import { cookies } from 'next/headers';

export async function refreshAndSetAccessToken() {
  // 从Cookie获取RefreshToken
  const refreshToken = cookies().get('refreshToken')?.value;
  if (!refreshToken) return null;

  try {
    // 调用后端刷新Token接口
    const response = await fetch(`${process.env.API_URL}/refresh-token`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refreshToken }),
    });

    if (!response.ok) throw new Error('Token刷新失败');
    const { accessToken: newAccessToken } = await response.json();

    // 将新AccessToken写入Cookie
    cookies().set('accessToken', newAccessToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge: 60 * 60 * 24, // 有效期1天,按需调整
    });

    return newAccessToken;
  } catch (err) {
    // 刷新失败,清除无效Cookie
    cookies().delete('accessToken');
    cookies().delete('refreshToken');
    return null;
  }
}

2. 修改Axios拦截器调用Server Action

更新服务端Axios实例的拦截器,调用上述Server Action获取新Token并重试请求:

import { refreshAndSetAccessToken } from '@/app/actions/auth.actions';
import axios from 'axios';

const instance = axios.create({ baseURL: process.env.API_URL });

instance.interceptors.response.use(
  (res) => res,
  async (error) => {
    if (error.response?.status === 401) {
      // 调用Server Action刷新Token并设置Cookie
      const newAccessToken = await refreshAndSetAccessToken();

      if (newAccessToken) {
        // 更新请求头的Authorization
        error.config.headers.Authorization = `Bearer ${newAccessToken}`;
        // 重试原请求
        return instance(error.config);
      } else {
        // 刷新失败,执行登出逻辑(如在Server环境可调用redirect跳转到登录页)
        // redirect('/login');
      }
    }

    return Promise.reject(error);
  },
);

export default instance;

关键说明

  • Server Action是Next.js14允许操作Cookie的合法环境,直接调用不会触发NEXT_REDIRECT错误(重定向仅适用于客户端跳转场景)
  • 拦截器仅负责错误捕获、调用Action获取Token、重试请求,所有Cookie操作都在Server Action中完成,符合Next.js规则
  • 保留了服务端请求的性能优势,无需切换到客户端Axios

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:41:19