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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:30:06