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