Next.js如何为特定路由条件式添加并堆叠中间件?
问题
根据Next.js文档,所有中间件需置于middleware.ts单文件中,通常默认作用于所有路径,写法形如middleware1(middleware2(middleware3))。我已编写了middleware.ts和StackMiddleware.ts代码如下:
middleware.ts 代码
import { NextFetchEvent, NextResponse, type NextRequest } from "next/server"; import { updateSession } from "@/utils/supabase/middleware"; import { redirect } from "next/navigation"; import { withHeaders } from "./middleware/withHeader"; import { withLogging } from "./middleware/withLogging"; import { StackMiddleware } from "./middleware/stackMiddleware"; export async function middleware( request: NextRequest, resposne: NextResponse, event: NextFetchEvent ) { const response = NextResponse.next(); if (request.nextUrl.pathname.startsWith("/test")) { // return NextResponse.rewrite(new URL("/about-2", request.url)); const middlewares = [withLogging, withHeaders]; StackMiddleware(middlewares); } const themePreference = response.cookies.get("theme"); if (!themePreference) { response.cookies.set("theme", "dark"); } await updateSession(request); return response; } export const config = { matcher: [ /* * Match all request paths except for the ones starting with: * - _next/static (static files) * - _next/image (image optimization files) * - favicon.ico (favicon file) * Feel free to modify this pattern to include more paths. */ "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", ], };
StackMiddleware.ts 代码
import { NextMiddleware, NextResponse } from "next/server"; import { MiddlewareFactory } from "./types"; export function StackMiddleware( functions: MiddlewareFactory[] = [], index = 0 ): NextMiddleware { const current = functions[index]; //Base case if (current) { const next = StackMiddleware(functions, index + 1); return current(next); } return () => NextResponse.next(); }
请问如何为特定路由条件式添加中间件?以本示例中的/test路由为例,该如何实现中间件堆叠?
解决方案
你当前的代码问题在于调用StackMiddleware(middlewares)后没有实际使用返回的中间件处理请求。要实现特定路由的中间件堆叠,需调整逻辑让中间件链真正参与请求处理,以下是具体修改步骤:
1. 确认MiddlewareFactory类型定义
确保middleware/types.ts中的类型符合标准,它应该是一个接收下一个中间件、返回新中间件的函数:
// middleware/types.ts import { NextMiddleware } from "next/server"; export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware;
2. 修改middleware.ts的路由处理逻辑
修正参数拼写错误,并让堆叠后的中间件链处理请求,返回最终响应:
import { NextFetchEvent, NextResponse, type NextRequest } from "next/server"; import { updateSession } from "@/utils/supabase/middleware"; import { withHeaders } from "./middleware/withHeader"; import { withLogging } from "./middleware/withLogging"; import { StackMiddleware } from "./middleware/stackMiddleware"; export async function middleware( request: NextRequest, event: NextFetchEvent // 修正原代码中第二个参数的拼写错误resposne ) { let response = NextResponse.next(); // 为/test路由应用中间件堆叠 if (request.nextUrl.pathname.startsWith("/test")) { // 创建整合后的中间件链 const middlewareChain = StackMiddleware([withLogging, withHeaders]); // 用中间件链处理请求,覆盖初始响应 response = await middlewareChain(request, event) || response; } // 全局逻辑:设置默认主题Cookie const themePreference = response.cookies.get("theme"); if (!themePreference) { response.cookies.set("theme", "dark"); } // 全局逻辑:更新Supabase会话 await updateSession(request); return response; } export const config = { matcher: [ "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", ], };
3. 确保单个中间件符合规范
withLogging和withHeaders需要遵循MiddlewareFactory的格式,接收下一个中间件并返回新的中间件:
示例:withLogging.ts
import { NextMiddleware, NextRequest } from "next/server"; import { MiddlewareFactory } from "./types"; export const withLogging: MiddlewareFactory = (next: NextMiddleware) => { return async (request: NextRequest, event: NextFetchEvent) => { console.log(`[LOG] 访问路径: ${request.nextUrl.pathname}`); // 执行下一个中间件 const response = await next(request, event); return response; }; };
示例:withHeaders.ts
import { NextMiddleware, NextRequest } from "next/server"; import { MiddlewareFactory } from "./types"; export const withHeaders: MiddlewareFactory = (next: NextMiddleware) => { return async (request: NextRequest, event: NextFetchEvent) => { const response = await next(request, event); // 为/test路由添加自定义响应头 response.headers.set("X-Test-Route", "true"); return response; }; };
关键说明
StackMiddleware返回的是一个整合后的中间件函数,必须传入request和event才会执行。- 中间件的执行顺序与数组顺序一致:先执行
withLogging,再执行withHeaders,最后执行默认的NextResponse.next()。 - 全局逻辑(如设置主题Cookie、更新会话)可放在条件分支外,确保所有路由都能执行,也可根据需求整合到中间件链中。
内容的提问来源于stack exchange,提问作者desh
相关产品推荐
相关产品推荐

