You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js14中next-auth与next-international中间件结合报错问题

Next.js 14 组合中间件问题:本地化与授权中间件冲突

问题背景

我正尝试为Next.js 14应用搭建组合中间件,目标是:

  • 所有路由都执行本地化中间件
  • /admin及子路由额外启用授权验证

但实际运行时出现问题:登录成功后重定向到/admin路由时,本地化中间件报错。

使用的依赖版本:

  • next-international: ^1.2.3
  • next-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*',
  ],
};

问题分析

  1. 参数定义错误:中间件函数的第二个参数并非NextRequestWithAuth,该类型是withAuth包装后的中间件才会传入的请求类型,原函数仅需request: NextRequest和event: NextFetchEvent两个参数。
  2. 逻辑顺序错误:当前代码中,/admin路由授权通过后(nextAuthResponse为空),会直接执行本地化中间件,但未考虑withAuth对请求上下文的修改,容易导致上下文不一致。
  3. 中间件调用方式错误:withAuth在授权通过时不会返回响应,而是允许请求继续执行,此时需要将处理后的请求传递给下一个中间件,而非仅判断返回值。
  4. 缺失核心导入:原代码未导入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:13:21