Featured image of post Next.js 中间件:路由、身份验证和边缘计算Featured image of post Next.js 中间件:路由、身份验证和边缘计算

Next.js 中间件:路由、身份验证和边缘计算

深入研究 Next.js 中间件的路由、身份验证、边缘计算、地理位置、A/B 测试和边缘运行时限制。

介绍

Next.js 中间件在每个请求之前执行,在边缘或无服务器区域运行。项目根目录下的单个 middleware.ts 文件会拦截传入请求,并可以在请求到达匹配路由之前重定向、重写、操作标头或执行身份验证检查。

中间件非常适合在页面渲染之前进行快速、基于边缘的决策。默认情况下,它不在静态资源或 _next/static 上运行。

基本结构

中间件文件导出一个接收 NextRequest 并返回 NextResponse 的函数,以及定义哪些路径触发执行的 config 对象。

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

export function middleware(request: NextRequest) {
  console.log(`Request: ${request.nextUrl.pathname}`);
  return NextResponse.next();
}

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};

matcher 配置使用带有负向前瞻的路径到正则表达式语法来排除静态文件。对于特定于部分的中间件,请使用多种模式,例如 ['/dashboard/:path*', '/admin/:path*']


认证与授权

在中间件中处理身份验证优于每页检查,因为它提供了单一事实来源并消除了页面转换时的闪烁。

export function middleware(request: NextRequest) {
  const token = request.cookies.get("session")?.value;
  const { pathname } = request.nextUrl;

  if (!token && pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  if (token && pathname.startsWith("/login")) {
    return NextResponse.redirect(new URL("/dashboard", request.url));
  }

  return NextResponse.next();
}

对于基于角色的访问,请在允许访问管理路由之前解码 JWT 或会话令牌并检查用户的角色。 NextAuth.js、Clerk 和 Auth0 都提供了简化此过程的中间件助手。


请求重写和重定向

中间件支持两种类型的 URL 操作。重写可在不更改浏览器 URL 的情况下提供不同的内容,而重定向则完全更改 URL。

export function middleware(request: NextRequest) {
  const { pathname, hostname } = request.nextUrl;

  const tenant = hostname.split(".")[0];
  if (tenant && tenant !== "www") {
    request.nextUrl.pathname = `/${tenant}${pathname}`;
    return NextResponse.rewrite(request.nextUrl);
  }
}

常见用例包括本地化登陆页面、功能门控内容以及基于子域或 cookie 值的多租户路由。


地理位置和个性化

边缘中间件通过 request.geo 提供地理位置数据,包括城市、国家、地区、纬度和经度。 request.ip 属性给出客户端 IP 地址。

export function middleware(request: NextRequest) {
  const { country } = request.geo;
  const { pathname } = request.nextUrl;

  if (["DE", "FR", "IT", "ES", "NL"].includes(country) && !pathname.startsWith("/gdpr")) {
    return NextResponse.redirect(new URL("/gdpr", request.url));
  }

  return NextResponse.next();
}

区域定价、内容本地化和 GDPR 同意路由都是基于地理位置的中间件逻辑的实际应用。


边缘运行时限制

中间件运行在 Edge Runtime 上,它有重要的限制:

限制详情
Node.js API不可用(无文件系统、加密、路径)
最大执行30 秒(目标是 1 秒以内)
捆绑尺寸1 MB 限制(代码加依赖项)
数据库无直接联系;使用 API 路由

保持中间件逻辑精简。使用 API 路由或服务器组件进行繁重的计算、数据库访问或文件系统操作。


结论

使用中间件进行快速、基于边缘的决策,例如身份验证、重定向和 URL 重写。保持逻辑简单,因为它在每个匹配的请求上运行。为了性能,优先使用 matcher 配置而不是函数内部的条件检查。使用 Playwright 或 Cypress 等工具将中间件行为与页面逻辑分开测试。