Next.js 15中Axios拦截器处理401调用redirect报错求助
问题:Next.js 15 + React 19中Axios拦截器调用redirect触发NEXT_REDIRECT错误
在Next.js 15和React 19项目中,尝试在Axios响应拦截器中调用Next.js的redirect方法处理401未授权错误时,触发了如下错误:
Error: NEXT_REDIRECT at <unknown> (file://project/apps/web/lib/axios.ts:36:15) at async Object.getProfile (file://project/apps/web/lib/api/user.ts:12:23) at async Page (file://project/apps/web/app/dashboard/page.tsx:4:22) 34 | async error => { 35 | if (error.response && error.response.status === 401) > 36 | redirect('/auth/login'); | ^ 37 | 38 | return Promise.reject(error); 39 | }, { digest: 'NEXT_REDIRECT;replace;/auth/login;307;' }
需要对/dashboard下的所有请求进行401错误校验,尝试过多种方案均无效,求解决思路。
用户提供的完整Axios配置代码:
'use server'; import axios from 'axios'; import { redirect } from 'next/navigation'; import { getSession } from './session'; const baseURL = process.env.NEXT_PUBLIC_BACKEND_URL; export const axiosInstance = axios.create({ baseURL, headers: { 'Content-Type': 'application/json', }, }); axiosInstance.interceptors.request.use( async config => { const session = await getSession(); if (session && session.accessToken) { config.headers.Authorization = `Bearer ${session.accessToken}`; } return config; }, error => { return Promise.reject(error); }, ); axiosInstance.interceptors.response.use( response => response, async error => { if (error.response && error.response.status === 401) redirect('/auth/login'); return Promise.reject(error); }, );
解决思路
1. 错误本质:redirect的工作机制与Axios拦截器的冲突
Next.js的redirect函数并非直接执行跳转逻辑,而是抛出一个特殊的NEXT_REDIRECT错误,由Next.js的路由系统捕获后处理跳转。但在Axios响应拦截器中调用redirect时,这个错误会被Axios的Promise错误处理链捕获,无法传递给Next.js的服务器组件/服务器动作上下文,因此直接暴露为未处理错误。
2. 可行解决方案
方案一:在API调用处统一捕获401并执行跳转
移除Axios拦截器中的redirect调用,改为抛出自定义标识的错误,然后在调用API的业务代码中捕获并处理跳转:
修改Axios响应拦截器:
axiosInstance.interceptors.response.use( response => response, async error => { if (error.response && error.response.status === 401) { // 抛出自定义错误标识 return Promise.reject(new Error('UNAUTHORIZED')); } return Promise.reject(error); }, );在Page组件或API调用函数中捕获错误:
// app/dashboard/page.tsx 'use server'; import { redirect } from 'next/navigation'; import { getProfile } from '@/lib/api/user'; export default async function Page() { try { const profile = await getProfile(); // 渲染页面内容 } catch (err) { if (err.message === 'UNAUTHORIZED') { redirect('/auth/login'); } // 处理其他类型错误 } }
方案二:提前在布局层做权限校验(推荐)
针对/dashboard这类需要授权的路由,直接在布局组件的顶层校验会话有效性,避免等到API返回401再处理,更符合Next.js的路由模型:
// app/dashboard/layout.tsx 'use server'; import { redirect } from 'next/navigation'; import { getSession } from '@/lib/session'; export default async function DashboardLayout({ children }) { const session = await getSession(); // 校验会话是否有效,无有效会话直接跳转登录页 if (!session?.accessToken) { redirect('/auth/login'); } return <div>{children}</div>; }
这种方式能提前拦截未授权访问,减少不必要的API请求,同时避免Axios拦截器与Next.js路由系统的冲突。
方案三:封装API调用函数统一处理401
将所有API调用封装到一个统一的函数中,在函数内部处理401错误并执行跳转,替代Axios拦截器的逻辑:
// lib/api/client.ts 'use server'; import { axiosInstance } from '../axios'; import { redirect } from 'next/navigation'; export async function apiCall(method: string, url: string, data?: any) { try { const response = await axiosInstance({ method, url, data }); return response.data; } catch (err) { if (err.response?.status === 401) { redirect('/auth/login'); } throw err; } }
使用时用apiCall代替直接调用axiosInstance:
// lib/api/user.ts import { apiCall } from './client'; export async function getProfile() { return apiCall('GET', '/user/profile'); }
内容的提问来源于stack exchange,提问作者Skyami
相关产品推荐
相关产品推荐

