Next.js14中next-auth与next-international中间件结合报错问题
Next.js 14 组合中间件问题:本地化与授权中间件冲突
问题背景
我正尝试为Next.js 14应用搭建组合中间件,目标是:
- 所有路由都执行本地化中间件
/admin及子路由额外启用授权验证
但实际运行时出现问题:登录成功后重定向到/admin路由时,本地化中间件报错。
使用的依赖版本:
next-international: ^1.2.3next-auth: ^4.24.5
当前代码
import { NextRequest, NextResponse, NextFetchEvent } from 'next/server'; import { NextRequestWithAuth, withAuth } from 'next-auth/middleware'; // 原代码缺失此导入,会导致运行时错误 import { createI18nMiddleware } from 'next-international/middleware'; const I18nMiddleware = createI18nMiddleware({ locales: ['en', 'sn'], defaultLocale: 'en', urlMappingStrategy: 'rewrite', }); const nextAuthMiddleware = withAuth({ pages: { signIn: '/login', }, }); export function middleware( request: NextRequest, requestAuth: NextRequestWithAuth, // 参数定义错误 event: NextFetchEvent, ) { const nextAuthResponse = nextAuthMiddleware(request, event); if (request.nextUrl.pathname.startsWith('/admin')) { if (nextAuthResponse) { return nextAuthResponse; } } if (request.nextUrl.pathname.startsWith('/')) { return I18nMiddleware(request); } return NextResponse.next(); } export const config = { matcher: [ '/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)', '/', '/admin/:path*', ], };
问题分析
- 参数定义错误:中间件函数的第二个参数并非
NextRequestWithAuth,该类型是withAuth包装后的中间件才会传入的请求类型,原函数仅需request: NextRequest和event: NextFetchEvent两个参数。 - 逻辑顺序错误:当前代码中,
/admin路由授权通过后(nextAuthResponse为空),会直接执行本地化中间件,但未考虑withAuth对请求上下文的修改,容易导致上下文不一致。 - 中间件调用方式错误:
withAuth在授权通过时不会返回响应,而是允许请求继续执行,此时需要将处理后的请求传递给下一个中间件,而非仅判断返回值。 - 缺失核心导入:原代码未导入
createI18nMiddleware,这会直接导致运行时错误。
修复方案
方案一:链式组合中间件
让/admin路由先经过授权验证,通过后再执行本地化逻辑;其他路由直接执行本地化中间件。
import { NextRequest, NextFetchEvent } from 'next/server'; import { withAuth } from 'next-auth/middleware'; import { createI18nMiddleware } from 'next-international/middleware'; const I18nMiddleware = createI18nMiddleware({ locales: ['en', 'sn'], defaultLocale: 'en', urlMappingStrategy: 'rewrite', }); // 为/admin路由创建组合中间件:先授权,再本地化 const adminMiddleware = withAuth( (request) => I18nMiddleware(request), { pages: { signIn: '/login', }, } ); export function middleware(request: NextRequest, event: NextFetchEvent) { if (request.nextUrl.pathname.startsWith('/admin')) { return adminMiddleware(request, event); } return I18nMiddleware(request); } export const config = { matcher: [ '/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)', ], };
方案二:匹配器层面拆分逻辑
通过withAuth的内置匹配器,仅对/admin路由启用授权,所有路由统一执行本地化。
import { NextRequest, NextFetchEvent } from 'next/server'; import { withAuth } from 'next-auth/middleware'; import { createI18nMiddleware } from 'next-international/middleware'; const I18nMiddleware = createI18nMiddleware({ locales: ['en', 'sn'], defaultLocale: 'en', urlMappingStrategy: 'rewrite', }); // 仅对/admin路由应用授权,授权通过后执行本地化 const authMiddleware = withAuth( (request) => I18nMiddleware(request), { pages: { signIn: '/login', }, matcher: '/admin/:path*' } ); export function middleware(request: NextRequest, event: NextFetchEvent) { if (request.nextUrl.pathname.startsWith('/admin')) { return authMiddleware(request, event); } return I18nMiddleware(request); } export const config = { matcher: [ '/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)', ], };
关键修复点
- 修正了中间件参数的错误定义,移除多余的
NextRequestWithAuth参数 - 补充了
createI18nMiddleware的核心导入 - 通过
withAuth包装本地化中间件的方式,确保授权与本地化逻辑的上下文一致性 - 简化了匹配器配置,避免重复路由匹配
内容的提问来源于stack exchange,提问作者Naynajith
相关产品推荐
相关产品推荐

