中间件 (Middleware)
中间件 (Middleware) 允许您在请求完成前运行代码。然后根据传入的请求,您可以通过重写、重定向、修改请求或响应头,或直接响应来修改响应。
中间件 (Middleware) 会在缓存内容和路由匹配之前运行。详见路径匹配。
使用场景
中间件 (Middleware) 特别适用的常见场景包括:
- 读取部分传入请求后快速重定向
- 基于 A/B 测试或实验重写到不同页面
- 修改所有页面或部分页面的头部信息
中间件 (Middleware) 不适合以下场景:
- 缓慢的数据获取
- 会话管理
约定
在项目根目录下使用 middleware.ts
(或 .js
)文件定义中间件 (Middleware)。例如,与 pages
或 app
同级,或在 src
目录内(如适用)。
注意:虽然每个项目仅支持一个
middleware.ts
文件,但您仍可以模块化组织中间件逻辑。将中间件功能拆分为单独的.ts
或.js
文件,然后导入到主middleware.ts
文件中。这样可以更清晰地管理特定路由的中间件,同时在middleware.ts
中集中控制。通过强制使用单一中间件文件,可以简化配置、避免潜在冲突,并通过避免多层中间件来优化性能。
示例
路径匹配
中间件 (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)
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
的匹配器会匹配。
条件语句
NextResponse
NextResponse
API 允许您:
- 将传入请求
redirect
到不同的 URL - 通过显示给定 URL 来
rewrite
响应 - 为 API 路由、
getServerSideProps
和rewrite
目标设置请求头 - 设置响应 cookie
- 设置响应头
要从中间件 (Middleware) 生成响应,您可以:
使用 Cookie
Cookie 是常规的头部信息。在 Request
中,它们存储在 Cookie
头中。在 Response
中,它们存储在 Set-Cookie
头中。Next.js 通过 NextRequest
和 NextResponse
上的 cookies
扩展提供了便捷的访问和操作方式。
- 对于传入请求,
cookies
提供以下方法:get
、getAll
、set
和delete
cookie。您可以使用has
检查 cookie 是否存在,或使用clear
删除所有 cookie。 - 对于传出响应,
cookies
提供以下方法:get
、getAll
、set
和delete
。
设置头部
您可以使用 NextResponse
API 设置请求和响应头(自 Next.js v13.0.0 起支持设置 请求 头)。
须知:避免设置过大的头部,因为这可能会根据后端 Web 服务器配置导致 431 请求头字段过大 错误。
CORS
您可以在中间件 (Middleware) 中设置 CORS 头以允许跨域请求,包括简单请求和预检请求。
须知:您可以在路由处理器中为单个路由配置 CORS 头。
生成响应
您可以直接从中间件返回一个 Response
或 NextResponse
实例来生成响应。(此功能自 Next.js v13.1.0 起可用)
waitUntil
和 NextFetchEvent
NextFetchEvent
对象扩展了原生的 FetchEvent
对象,并包含 waitUntil()
方法。
waitUntil()
方法接收一个 Promise 作为参数,并延长中间件的生命周期直到该 Promise 完成。这对于在后台执行工作非常有用。
高级中间件标志
在 Next.js 的 v13.1
版本中,引入了两个额外的中间件标志 skipMiddlewareUrlNormalize
和 skipTrailingSlashRedirect
来处理高级用例。
skipTrailingSlashRedirect
禁用了 Next.js 用于添加或移除尾部斜杠的重定向。这允许在中间件内进行自定义处理,为某些路径保留尾部斜杠而不为其他路径保留,从而使得增量迁移更加容易。
skipMiddlewareUrlNormalize
允许禁用 Next.js 中的 URL 规范化,使得直接访问和客户端跳转的处理方式一致。在某些高级用例中,此选项通过使用原始 URL 提供了完全控制。
单元测试(实验性功能)
从 Next.js 15.1 开始,next/experimental/testing/server
包提供了用于单元测试中间件文件的工具。单元测试中间件有助于确保它仅在所需的路径上运行,并且自定义的路由逻辑在生产环境之前按预期工作。
unstable_doesMiddlewareMatch
函数可用于断言中间件是否会针对提供的 URL、标头和 Cookie 运行。
也可以测试整个中间件函数。
运行时
中间件默认使用 Edge 运行时。从 v15.2(canary 版本)开始,我们实验性地支持使用 Node.js 运行时。要启用此功能,请在 next.config
文件中添加标志:
然后在中间件文件中,将 config
对象中的运行时设置为 nodejs
:
注意:此功能尚不建议在生产环境中使用。因此,除非您使用的是 next@canary 版本而非稳定版本,否则 Next.js 会抛出错误。
平台支持
部署选项 | 是否支持 |
---|---|
Node.js 服务器 | 是 |
Docker 容器 | 是 |
静态导出 | 否 |
适配器 | 取决于具体平台 |
了解如何配置中间件以自托管 Next.js。