Next.js App Router:如何在401响应时自动触发登出重定向
统一处理Next.js请求401自动重定向的方案
要在请求封装工具里统一处理401重定向,核心是区分服务端/客户端环境——Next.js里两者的重定向API完全不同,不能混用。下面分App Router(Next.js 13+)和Pages Router两种场景给出具体实现:
一、App Router(Next.js 13+)场景
1. 编写带401处理的fetch封装
直接在封装函数里判断环境,调用对应重定向逻辑:
import { redirect } from 'next/navigation'; export async function fetchWithAuth(url, options = {}) { const isServer = typeof window === 'undefined'; const response = await fetch(url, { ...options, // 统一配置请求凭证、headers等,按需调整 credentials: 'include', headers: { 'Content-Type': 'application/json', ...options.headers, }, }); // 捕获401状态码 if (response.status === 401) { if (isServer) { // 服务端组件:调用Next.js官方redirect函数,触发服务端重定向 // 注:这个函数会抛出特殊错误,Next.js会自动处理重定向,无需额外catch redirect('/logout'); } else { // 客户端组件:直接跳转,也可以用useRouter(需在客户端组件中使用) window.location.href = '/logout'; // 若用客户端useRouter: // const router = useRouter(); // router.push('/logout'); } // 抛出错误终止后续逻辑 throw new Error('未授权,正在跳转到登录页'); } return response; }
2. 服务端组件中使用
直接调用封装函数即可,无需手动检查状态码:
// 服务端组件示例 import { fetchWithAuth } from '@/utils/fetchWithAuth'; export default async function UserProfile() { // 请求返回401时会自动重定向到logout const userRes = await fetchWithAuth('/api/user/profile'); const userData = await userRes.json(); return <div>用户名:{userData.name}</div>; }
3. 客户端组件中使用
客户端组件调用时,会自动触发客户端跳转:
'use client'; import { fetchWithAuth } from '@/utils/fetchWithAuth'; import { useState, useEffect } from 'react'; export default function UserDashboard() { const [userData, setUserData] = useState(null); useEffect(() => { fetchWithAuth('/api/user/dashboard') .then(res => res.json()) .then(data => setUserData(data)) .catch(err => console.log(err)); }, []); return userData ? <div>仪表盘:{userData.stats}</div> : <div>加载中...</div>; }
二、Pages Router(Next.js 12及更早)场景
Pages Router的服务端重定向依赖res对象或getServerSideProps返回值,封装时需做适配:
1. 编写带401处理的fetch封装
export async function fetchWithAuth(url, options = {}, res) { const isServer = typeof window === 'undefined'; const response = await fetch(url, { ...options, credentials: 'include', }); if (response.status === 401) { if (isServer && res) { // API路由或getServerSideProps中,用res对象重定向 res.writeHead(302, { Location: '/logout' }); res.end(); } else if (isServer) { // getServerSideProps中,返回重定向对象 return { redirect: { destination: '/logout', permanent: false, }, }; } else { // 客户端直接跳转 window.location.href = '/logout'; } throw new Error('未授权'); } return response; }
2. 在getServerSideProps中使用
export async function getServerSideProps(context) { try { const response = await fetchWithAuth('/api/user', {}, context.res); const userData = await response.json(); return { props: { userData } }; } catch (err) { // 若封装函数返回重定向对象,直接返回 if (err.redirect) { return err.redirect; } return { props: {} }; } }
关键注意事项
- 服务端绝对不能调用
window相关API,环境判断typeof window === 'undefined'必须准确。 - App Router服务端组件中,
redirect函数通过抛出错误实现,调用后一定要抛出错误终止后续代码,避免逻辑混乱。 - 若在API路由中处理401,服务端可直接返回
new Response(null, { status: 401 })让客户端统一捕获,也可用对应重定向API直接跳转。
内容的提问来源于stack exchange,提问作者ssantos
相关产品推荐
相关产品推荐

