中间件 (Middleware)
中间件允许您在请求完成前运行代码。然后根据传入的请求,您可以通过重写、重定向、修改请求或响应头,或直接响应来修改响应。
中间件在缓存内容和路由匹配之前运行。详见路径匹配获取更多细节。
使用场景
将中间件集成到您的应用中可以显著提升性能、安全性和用户体验。以下是一些中间件特别有效的常见场景:
- 认证与授权:在授予特定页面或API路由访问权限前验证用户身份并检查会话cookie
- 服务端重定向:根据特定条件(如语言区域、用户角色)在服务器级别重定向用户
- 路径重写:支持A/B测试、功能发布或旧版路径,根据请求属性动态重写API路由或页面的路径
- 机器人检测:通过检测和拦截机器人流量来保护您的资源
- 日志与分析:在页面或API处理前捕获并分析请求数据以获取洞察
- 功能开关:动态启用或禁用功能以实现无缝功能发布或测试
认识到中间件可能不是最优解决方案的场景同样重要。以下是一些需要注意的情况:
- 复杂数据获取与操作:中间件不适用于直接数据获取或操作,这些操作应在路由处理器 (Route Handlers) 或服务端实用程序中完成
- 繁重的计算任务:中间件应保持轻量级并快速响应,否则可能导致页面加载延迟。繁重的计算任务或长时间运行的处理应在专门的路由处理器中完成
- 复杂的会话管理:虽然中间件可以处理基本会话任务,但复杂的会话管理应由专门的认证服务或在路由处理器中处理
- 直接数据库操作:不建议在中间件中执行直接数据库操作。数据库交互应在路由处理器或服务端实用程序中完成
约定
在项目根目录使用 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
NextResponse
API 允许您:
- 将传入请求
redirect
到不同的URL - 通过显示给定URL来
rewrite
响应 - 为API路由、
getServerSideProps
和rewrite
目标设置请求头 - 设置响应cookie
- 设置响应头
要从中间件生成响应,您可以:
rewrite
到生成响应的路由(页面 或 Edge API路由)- 直接返回
NextResponse
。参见生成响应
使用Cookie
Cookie是常规的头部信息。在 Request
中,它们存储在 Cookie
头中。在 Response
中,它们位于 Set-Cookie
头中。Next.js 通过 NextRequest
和 NextResponse
上的 cookies
扩展提供了一种便捷的方式来访问和操作这些cookie。
- 对于传入请求,
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 (跨源资源共享)
您可以在中间件中设置 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 提供了完全控制。
运行时
中间件目前仅支持 Edge 运行时,无法使用 Node.js 运行时。