Next.js 14中间件重定向异常:鉴权失败未跳转至登录页
问题分析与解决方案
核心原因
你遇到的问题是异步请求(fetch/Server Action)不会自动触发浏览器页面跳转:
- Middleware返回的
NextResponse.redirect()仅作用于当前的fetch请求本身,服务器会返回302状态码和目标URL,但浏览器不会自动跳转到该URL——因为这是后台异步请求,不是用户触发的页面级导航。 - 控制台日志显示
GET /auth/login 200是服务器成功处理了重定向请求,但客户端没有对这个响应做跳转处理,因此页面停留在原路由。
解决方案
1. 客户端fetch请求手动处理重定向
在发起fetch请求的客户端代码中,检查响应的redirected属性或状态码,手动触发页面跳转:
async function fetchProtectedResource() { const res = await fetch('/api/testurl/your-path', { credentials: 'include' // 必须携带cookie,否则Middleware无法鉴权 }); // 检测到重定向时手动跳转 if (res.redirected) { window.location.href = res.url; return; } // 处理正常响应或其他错误 if (!res.ok) { const error = await res.json(); console.error('请求失败:', error); return; } const data = await res.json(); // 处理业务数据 }
2. 针对API路由返回401而非重定向
修改Middleware逻辑,对API类请求返回401 Unauthorized状态码,让客户端更易处理:
export async function middleware(request: Request) { const cookies = request.headers.get('cookie'); const isApiRequest = request.url.includes('/api/'); // 判断是否为API请求 // 无cookie的情况 if (!cookies) { if (isApiRequest) { return new NextResponse(JSON.stringify({ error: '未授权' }), { status: 401 }); } return NextResponse.redirect(new URL('/auth/login', request.url)); } // ... 其余鉴权逻辑保持不变 ... // 示例:在无accessToken时的处理 if (!accessToken) { console.log('No access token found'); if (isApiRequest) { return new NextResponse(JSON.stringify({ error: '未授权' }), { status: 401 }); } const redirectUrl = new URL('/auth/login', request.url); console.log('Redirecting to:', redirectUrl.toString()); return NextResponse.redirect(redirectUrl); } // ... 其余鉴权逻辑保持不变 ... }
之后客户端可以捕获401状态码,再触发跳转:
async function fetchProtectedResource() { try { const res = await fetch('/api/testurl/your-path', { credentials: 'include' }); if (res.status === 401) { window.location.href = '/auth/login'; return; } // 处理正常响应 } catch (err) { console.error(err); } }
3. Server Action中处理鉴权跳转
如果使用Server Action,可以直接在Action内部捕获未授权情况,调用Next.js的redirect函数:
'use server'; import { redirect } from 'next/navigation'; export async function getProtectedData() { const res = await fetch('/api/testurl/your-path', { credentials: 'include', headers: { 'Content-Type': 'application/json' } }); if (res.redirected || res.status === 401) { redirect('/auth/login'); } if (!res.ok) { throw new Error('请求失败'); } return res.json(); }
关键区别
- 页面导航请求(直接输入URL、点击
Link组件):Middleware的重定向会直接触发浏览器跳转,无需额外处理。 - 异步请求(fetch/Server Action):必须通过客户端代码或Server Action主动处理跳转逻辑。
内容的提问来源于stack exchange,提问作者Vaclav Vlcek
相关产品推荐
相关产品推荐

