Next.js生产环境App Router中间件未正常执行问题
Next.js 14 App Router 中间件生产环境认证失效问题修复
问题背景
将项目从 Pages Router 迁移到 App Router 后,使用了(main)和(auth)两个路由组分别对应首页/和认证页/auth,中间件逻辑为:
- 未认证用户访问
/时自动跳转至/auth - 已认证用户访问
/auth时自动跳转至/
该逻辑在本地开发环境正常,但生产环境下出现校验失效,未认证用户偶尔能访问/,已认证用户偶尔能访问/auth。
项目采用src目录结构,middleware.ts与src/app同级,目录结构如下:
|-- src |--- app |---- (main) |----- layout.tsx |----- page.tsx |---- (auth) |----- layout.tsx |----- page.tsx |---- layout.tsx |--- middleware.ts
核心问题分析
- 生产环境静态缓存:App Router 对静态页面默认启用缓存,若
page.tsx未配置动态渲染,生产环境会直接返回缓存页面,跳过中间件校验。 - Cookie 获取方式兼容性:使用
cookies()全局 API 在生产环境可能存在上下文传递问题,不如直接从请求对象获取可靠。 - 路由匹配精度:原 matcher 规则虽排除了静态资源,但未明确指定目标路由,可能导致部分请求未触发中间件。
修复方案
1. 强制页面动态渲染
在(main)/page.tsx和(auth)/page.tsx中添加动态渲染配置,确保每次请求都经过中间件:
// src/app/(main)/page.tsx export const dynamic = 'force-dynamic' // 禁用静态缓存,强制每次请求触发中间件 export default function MainPage() { // 页面内容 }
// src/app/(auth)/page.tsx export const dynamic = 'force-dynamic' export default function AuthPage() { // 页面内容 }
2. 修改中间件代码
优化 Cookie 获取方式,明确路由匹配规则,移除不必要的异步标记:
import { NextRequest, NextResponse } from 'next/server' const protectedRoutes = ['/'] const publicRoutes = ['/auth'] export function middleware(req: NextRequest) { const path = req.nextUrl.pathname const isProtectedRoute = protectedRoutes.includes(path) const isPublicRoute = publicRoutes.includes(path) // 直接从请求对象获取 Cookie,避免全局 API 上下文问题 const token = req.cookies.get('token')?.value // 未认证访问受保护路由,跳转到认证页 if (isProtectedRoute && !token) { const redirectUrl = req.nextUrl.clone() redirectUrl.pathname = '/auth' return NextResponse.redirect(redirectUrl) } // 已认证访问公共路由,跳转到首页 if (isPublicRoute && token) { const redirectUrl = req.nextUrl.clone() redirectUrl.pathname = '/' return NextResponse.redirect(redirectUrl) } return NextResponse.next() } export const config = { matcher: [ // 明确指定需要校验的路由,同时排除静态资源与 API '/', '/auth', '/((?!api|_next/static|_next/image|favicon.ico|.*\\.png$).*)' ], }
3. 检查生产环境 Cookie 配置
设置认证 Cookie 时,需适配生产环境的 HTTPS 环境,确保 Cookie 能被正确传递:
// 示例:在 API 路由中设置 Cookie import { NextResponse } from 'next/server' export async function POST(req: Request) { // 认证逻辑... const token = 'your-auth-token' const response = NextResponse.json({ success: true }) response.cookies.set({ name: 'token', value: token, httpOnly: true, secure: process.env.NODE_ENV === 'production', // 生产环境开启 Secure 属性 sameSite: 'lax', path: '/', maxAge: 60 * 60 * 24 * 7 // 一周有效期 }) return response }
4. 部署配置验证
确认部署平台(如 Vercel、Netlify)正确识别src/middleware.ts,未忽略该文件的打包与执行。
验证步骤
- 生产环境部署后,打开浏览器开发者工具的「Network」面板
- 未认证状态下访问
/,检查是否触发 307 重定向至/auth - 已认证状态下访问
/auth,检查是否触发 307 重定向至/ - 查看请求头中的 Cookie 是否正确携带
token字段
内容的提问来源于stack exchange,提问作者Felipe Gouvêa
相关产品推荐
相关产品推荐

