如何使用 middleware.ts 文件在 Next.js 中使用多个中间件?

l D*_*e l 27 javascript web-frontend reactjs next.js next.js13

我正在开发一个 Next.js 项目,并尝试在我的应用程序中实现多个中间件。虽然我发现了使用该包在 Next.js 中使用单个中间件的示例next-connect,但我更喜欢在不依赖任何外部包的情况下实现此目的。

我有一个middleware.ts文件,我想在其中定义和使用多个中间件。这是我的文件中的代码片段middleware.ts

import { NextResponse, NextRequest } from 'next/server';

export function middleware(request: NextRequest) {

  const userId = request.cookies.get('userId')

  if (!userId) {
    return NextResponse.redirect(new URL('/auth/login', request.nextUrl.origin).href);
  }
  return NextResponse.next();
}

export const config = {
    matcher:'/profile/:path*',
};
Run Code Online (Sandbox Code Playgroud)

她是我尝试过的:

import { NextResponse, NextRequest } from "next/server";

export function profileMiddleware(request: NextRequest) {
  const userId = request.cookies.get("userId");

  if (!userId) {
    return NextResponse.redirect(
      new URL("/auth/login", request.nextUrl.origin).href
    );
  }
  return NextResponse.next();
}

export function authMiddleware(request: NextRequest) {
  const userId = request.cookies.get("userId");

  if (userId) {
    return NextResponse.redirect(
      new URL("/", request.nextUrl.origin).href
    );
  }
  return NextResponse.next();
}

export default {
  middleware: [
    {
      matcher: '/profile/:path*',
      handler: profileMiddleware,
    },
    {
      matcher: '/auth/:path*',
      handler: authMiddleware,
    },
  ],
};
Run Code Online (Sandbox Code Playgroud)

小智 21

您可以使用中间件链接来实现此目的。以下是实现这一目标的方法:

  1. 创建一个名为middlewaresin 您的src文件夹的文件夹。
  2. stackHandler.ts在该文件夹中创建一个名为的文件middlewares并将以下内容粘贴到其中:

import {
  NextMiddleware,
  NextResponse
} from "next/server";

export function stackMiddlewares(functions: MiddlewareFactory[] = [], index = 0): NextMiddleware {
  const current = functions[index];
  if (current) {
    const next = stackMiddlewares(functions, index + 1);
    return current(next);
  }
  return () => NextResponse.next();
}
Run Code Online (Sandbox Code Playgroud)

  1. 创建另一个名为的文件withUser.ts并将以下内容粘贴到其中:

import {
  NextFetchEvent,
  NextRequest,
  NextResponse
} from "next/server";

function getSearchParam(param: string, url: any) {
  return url.searchParams.get(param);
}

export const withUser: MiddlewareFactory = (next) => {
  return async(request: NextRequest, _next: NextFetchEvent) => {
    const pathname = request.nextUrl.pathname;

    if (["/profile"]?.some((path) => pathname.startsWith(path))) {
      const userId = request.cookies.get("userId");
      if (!userId) {
        const url = new URL(`/auth/login`, request.url);
        return NextResponse.redirect(url);
      }
    }
    return next(request, _next);
  };
};
Run Code Online (Sandbox Code Playgroud)

  1. 最后在文件夹middleware.ts中的文件中src粘贴以下内容:

import {
  stackMiddlewares
} from "@/middlewares/stackHandler";
import {
  withUser
} from "@/middlewares/withUser";

const middlewares = [withUser];
export default stackMiddlewares(middlewares);
Run Code Online (Sandbox Code Playgroud)

笔记

定义 MiddlewareFactory 类型如下(如果不使用 Typescript,请忽略此):

import {
  NextMiddleware
} from "next/server";

export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware;
Run Code Online (Sandbox Code Playgroud)

笔记

您可以withUser根据需要创建任意数量的中间件,方法是创建它们,然后将它们导入middlewares.ts并推送到middlewares数组中。

  • @crollywood `["/profile"].some((path) => pathname.startsWith(path))` 是一个自定义匹配器,如果您需要运行路由的中间件函数,则需要在每个中间件函数中使用它/路径子集。声明性 next.js 中间件配置/匹配器将限制所有中间件,这对于寻找多个中间件的人来说可能是不受欢迎的。有趣的是,10 年前 Express 就有很好的中间件,而接下来只支持一个。也许是因为指定执行顺序会更困难? (3认同)