在Next.js中使用原生fetch时是否有类似axios拦截器的实现方案?
Next.js 原生fetch实现拦截器方案
以下两种方案可以完美替代axios拦截器的能力,实现统一添加token、统一处理响应等逻辑:
方案1:封装自定义fetch工具(最推荐)
这种方法不会污染全局fetch,灵活度最高,客户端、服务端场景通用:
- 第一步:新建工具文件
src/utils/fetchWithAuth.ts,写入以下逻辑:
export const fetchWithAuth = async (input: RequestInfo | URL, init?: RequestInit) => { // ========== 请求拦截逻辑开始 ========== let token: string | null = null; // 客户端场景从localStorage获取token if (typeof window !== 'undefined') { token = localStorage.getItem('auth_token'); } // 服务端场景(Next.js 13+ App Router)从cookie获取token else { const { cookies } = await import('next/headers'); token = cookies().get('auth_token')?.value || null; } // 合并自定义请求头 const headers = new Headers(init?.headers); if (token) { headers.set('Authorization', `Bearer ${token}`); } // 可根据需求添加其他公共请求头 if (!headers.has('Content-Type')) { headers.set('Content-Type', 'application/json'); } const modifiedInit: RequestInit = { ...init, headers }; // ========== 请求拦截逻辑结束 ========== const response = await fetch(input, modifiedInit); // ========== 响应拦截逻辑开始 ========== // 统一处理401未授权跳转登录 if (response.status === 401) { if (typeof window !== 'undefined') { window.location.href = '/login'; } else { const { redirect } = await import('next/navigation'); redirect('/login'); } } // 可扩展其他响应处理逻辑:统一报错提示、格式化返回数据等 // ========== 响应拦截逻辑结束 ========== return response; };
- 第二步:替换项目中原生
fetch调用,直接使用fetchWithAuth即可,用法和原生fetch完全一致,不需要额外手动添加token:
// 示例请求 const getUserInfo = async () => { const res = await fetchWithAuth('/api/user/info', { method: 'GET' }); return await res.json(); };
方案2:全局重写原生fetch
如果不想修改项目中已有的大量fetch调用,可以直接重写全局fetch方法,实现全局拦截:
客户端全局拦截
在根客户端布局文件(app/layout.tsx标记'use client')的useEffect中添加以下逻辑:
'use client'; import { useEffect } from 'react'; export default function RootLayout({ children }) { useEffect(() => { const originalFetch = window.fetch; window.fetch = async (input, init) => { // 请求拦截:统一加token const token = localStorage.getItem('auth_token'); const headers = new Headers(init?.headers); if (token) { headers.set('Authorization', `Bearer ${token}`); } const modifiedInit = { ...init, headers }; const res = await originalFetch(input, modifiedInit); // 响应拦截:统一处理401 if (res.status === 401) { window.location.href = '/login'; } return res; }; }, []); return <html><body>{children}</body></html> }
服务端全局拦截
如果需要服务端请求也统一加拦截,可以在middleware.ts中统一处理请求头,或者在服务端逻辑入口重写全局fetch方法。
内容的提问来源于stack exchange,提问作者mingxingwang
相关产品推荐
相关产品推荐

