中间件(Middleware)
Middleware 允许你在请求完成之前运行代码。然后,基于传入的请求,你可以通过重写、重定向、修改请求或响应 header,或直接响应来修改响应。
Middleware 在缓存内容和路由匹配之前运行。更多详情请参阅 匹配路径。
将 Middleware 集成到你的应用程序中可以显著提升性能、安全性和用户体验。以下是 Middleware 特别有效的一些常见场景:
- 身份验证和授权:在授予对特定页面或 API 路由的访问权限之前,确认用户身份并检查会话 cookie。
- 服务器端重定向:基于某些条件 (例如:地区、用户角色) 在服务器级别重定向用户。
- 路径重写:根据请求属性动态重写 API 路由或页面的路径,支持 A/B 测试、功能发布或保留旧路径。
- 机器人检测:通过检测和阻止机器人流量来保护你的资源。
- 日志和分析:在页面或 API 处理之前捕获和分析请求数据以获得洞察。
- 功能标记:动态启用或禁用功能,实现无缝功能发布或测试。
认识到 middleware 可能不是最佳方案的情况同样重要。以下是需要注意的一些场景:
- 复杂的数据获取和处理:Middleware 不适合直接获取或处理数据,这些应该在 Route Handler 或服务器端工具中完成。
- 重计算任务:Middleware 应该轻量且快速响应,否则会导致页面加载延迟。重计算任务或长时间运行的进程应该在专门的 Route Handler 中完成。
- 大量会话管理:虽然 Middleware 可以管理基本的会话任务,但大量的会话管理应该由专门的认证服务或在 Route Handler 中管理。
- 直接数据库操作:不建议在 Middleware 中执行直接的数据库操作。数据库交互应该在 Route Handler 或服务器端工具中完成。
在项目根目录使用 middleware.ts
(或 .js
) 文件来定义 Middleware。例如,与 pages
或 app
目录同级,或者如果适用的话放在 src
目录内。
注意:虽然每个项目只支持一个 middleware.ts
文件,但你仍然可以模块化组织你的 middleware 逻辑。将 middleware 功能拆分到单独的 .ts
或 .js
文件中,然后将它们导入到主 middleware.ts
文件中。这允许对特定路由的 middleware 进行更清晰的管理,并在 middleware.ts
中集中控制。通过强制使用单个 middleware 文件,可以简化配置、防止潜在冲突,并通过避免多层 middleware 来优化性能。
Middleware 将对项目中的每个路由执行。鉴于此,使用 matcher 来精确定位或排除特定路由至关重要。以下是执行顺序:
next.config.js
中的 headers
next.config.js
中的 redirects
- Middleware (
rewrites
、redirects
等)
next.config.js
中的 beforeFiles
(rewrites
)
- 文件系统路由 (
public/
、_next/static/
、pages/
、app/
等)
next.config.js
中的 afterFiles
(rewrites
)
- 动态路由 (
/blog/[slug]
)
next.config.js
中的 fallback
(rewrites
)
有两种方式来定义 Middleware 运行的路径:
- 自定义匹配器配置
- 条件语句
matcher
允许你过滤 Middleware 在特定路径上运行。
你可以用数组语法匹配单个路径或多个路径:
matcher
配置支持完整的正则表达式,因此支持像负向前瞻或字符匹配这样的匹配。这里是一个使用负向前瞻来匹配除特定路径外的所有路径的例子:
你也可以使用 missing
或 has
数组,或它们的组合来绕过某些请求的 Middleware:
值得注意的是:matcher
值需要是常量,这样它们就可以在构建时进行静态分析。动态值比如变量将被忽略。
配置的匹配器:
- 必须以
/
开头
- 可以包含命名参数:
/about/:path
匹配 /about/a
和 /about/b
但不匹配 /about/a/c
- 命名参数 (以
:
开头) 可以有修饰符:/about/:path*
匹配 /about/a/b/c
因为 *
是 零个或多个。?
是 零个或一个 而 +
是 一个或多个
- 可以使用括号中的正则表达式:
/about/(.*)
等同于 /about/:path*
在 path-to-regexp 文档中了解更多详情。
值得注意的是:为了向后兼容,Next.js 始终将 /public
视为 /public/index
。因此,/public/:path
的 matcher 将匹配。
NextResponse
API 允许你:
redirect
将传入请求重定向到不同的 URL
rewrite
通过显示给定的 URL 来重写响应
- 为 API 路由、
getServerSideProps
和 rewrite
目标设置请求 header
- 设置响应 cookie
- 设置响应 header
要从 Middleware 产生响应,你可以:
rewrite
到一个产生响应的路由 (页面 或 路由处理程序)
- 直接返回一个
NextResponse
。参见 产生响应
Cookie 是常规的 header。在 Request
中,它们存储在 Cookie
header 中。在 Response
中,它们在 Set-Cookie
header 中。Next.js 通过 NextRequest
和 NextResponse
上的 cookies
扩展提供了一种便捷的方式来访问和操作这些 cookie。
- 对于传入的请求,
cookies
提供以下方法:get
、getAll
、set
和 delete
cookie。你可以用 has
检查 cookie 是否存在,或用 clear
删除所有 cookie。
- 对于传出的响应,
cookies
有以下方法:get
、getAll
、set
和 delete
。
你可以使用 NextResponse
API 设置请求和响应 header (设置请求 header 从 Next.js v13.0.0 开始可用)。
值得注意的是:避免设置大型 header,因为这可能会导致 431 请求 Header 字段过大 错误,具体取决于你的后端 web 服务器配置。
你可以在 Middleware 中设置 CORS header 以允许跨源请求,包括 简单请求 和 预检请求。
值得注意的是:你可以为 路由处理程序 中的单个路由配置 CORS header。
你可以通过返回一个 Response
或 NextResponse
实例从 Middleware 直接响应。(这个功能从 Next.js v13.1.0 开始可用)
NextFetchEvent
对象扩展了原生的 FetchEvent
对象,并包含 waitUntil()
方法。
waitUntil()
方法接受一个 promise 作为参数,并延长 Middleware 的生命周期直到 promise 解决。这对于执行后台工作很有用。
在 Next.js 的 v13.1
中引入了两个额外的 middleware 标志,skipMiddlewareUrlNormalize
和 skipTrailingSlashRedirect
,用于处理高级用例。
skipTrailingSlashRedirect
禁用 Next.js 添加或删除尾部斜杠的重定向。这允许在 middleware 中自定义处理,为某些路径保留尾部斜杠但其他路径不保留,这可以使增量迁移更容易。
skipMiddlewareUrlNormalize
允许禁用 Next.js 中的 URL 规范化,使直接访问和客户端转换的处理相同。在一些高级情况下,这个选项通过使用原始 URL 提供完全控制。
Middleware 目前只支持与 Edge 运行时 兼容的 API。Node.js 独有的 API 不支持。
版本 | 变更 |
---|
v13.1.0 | 添加高级 Middleware 标志 |
v13.0.0 | Middleware 可以修改请求 header、响应 header,并发送响应 |
v12.2.0 | Middleware 稳定版,请参阅 升级指南 |
v12.0.9 | 在 Edge Runtime 中强制使用绝对 URL (PR) |
v12.0.0 | 添加 Middleware (测试版) |