我正在开发一个 Next.js 14 App Router 项目,我需要集成两个中间件: Kinde 身份验证中间件(用于受保护的路由,如 /dashboard)。 next-intl 中间件(用于 /en 或 /de 等路由上的国际化)。 由于 Next.js 仅支持单个中间件导出,因此我无法使用两个单独的中间件。这是我的代码的样子:
import createMiddleware from 'next-intl/middleware';
import {routing} from '@/i18n/routing';
export default createMiddleware(routing);
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(en|fr|ar)/:path*']
};
import {
authMiddleware,
withAuth,
} from "@kinde-oss/kinde-auth-nextjs/middleware";
export default function middleware(req: Request) {
return withAuth(req);
}
export const config = {
matcher: ["/dashboard"],
};
我考虑在同一个文件中调用两个中间件函数,但我不确定如何正确构建逻辑来处理身份验证和国际化。
创建一个名为
middlewares
的文件夹,其中包含以下文件:
import {
NextResponse,
type NextFetchEvent,
type NextRequest
} from 'next/server'
import { CustomMiddleware } from './chain'
import createMiddleware from "next-intl/middleware";
import {routing} from "@/i18n/routing";
export function withI18nMiddleware(middleware: CustomMiddleware) {
return async (request: NextRequest, event: NextFetchEvent) => {
// The first middleware in the chain has to create the response
// Internationalisation with next-intl middleware
const handleI18nRouting = createMiddleware(routing);
console.log("middleware ai18n called")
let response = NextResponse.next()
try {
response = handleI18nRouting(request)
}catch (e){
console.log("error in i18n middleware", e)
}
// Call the next middleware and pass the request and response
return middleware(request, event, response)
}
}
import {
NextResponse,
type NextFetchEvent,
type NextRequest
} from 'next/server'
import { CustomMiddleware } from './chain'
import {
authMiddleware,
withAuth,
} from "@kinde-oss/kinde-auth-nextjs/middleware";
export function withAuthMiddleware(middleware: CustomMiddleware) {
return async (
request: NextRequest,
event: NextFetchEvent,
response: NextResponse
) => {
// Check the authentication using Kinde-Auth middleware
const protectedRoutes = ['/dashboard', '/en/dashboard', '/fr/dashboard', '/ar/dashboard'];
const isProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route));
if (isProtectedRoute) {
console.log("middleware auth called")
return withAuth(request);
}else {
// Call the next middleware and pass the request and response
return middleware(request, event, response)
}
}
}
import { NextMiddlewareResult } from 'next/dist/server/web/types'
import { NextResponse } from 'next/server'
import type { NextFetchEvent, NextRequest } from 'next/server'
export type CustomMiddleware = (
request: NextRequest,
event: NextFetchEvent,
response: NextResponse
) => NextMiddlewareResult | Promise<NextMiddlewareResult>
type MiddlewareFactory = (middleware: CustomMiddleware) => CustomMiddleware
export function chain(
functions: MiddlewareFactory[],
index = 0
): CustomMiddleware {
const current = functions[index]
console.log("middleware called")
if (current) {
const next = chain(functions, index + 1)
return current(next)
}
return (
request: NextRequest,
event: NextFetchEvent,
response: NextResponse
) => {
return response
}
}
然后在middlware.ts里面放入代码:
import { chain } from '@/middlewares/chain'
import {withI18nMiddleware} from "@/middlewares/i18nMiddleware";
import {withAuthMiddleware} from "@/middlewares/authMiddleware";
const middlewares = [ withI18nMiddleware, withAuthMiddleware]
export default chain(middlewares)
export const config = {
// Match only internationalized pathnames
matcher: ['/', '/(en|fr|ar)/:path*']
};