内容提要
Supabase 发布 @supabase/middleware,为 Web Fetch 处理器提供可组合、类型安全的中间件。开发者编写一次每请求逻辑,即可在任意支持 fetch 的运行时及 Hono、NestJS 等框架中复用。内置 CORS、JWT 验证、客户端注入等中间件,支持自定义扩展与打包共享,采用 MIT 许可,不绑定 Supabase。
延伸解读
中间件引擎的独立性与可移植性
Supabase 中间件引擎不依赖 Supabase 项目、数据库或账户,采用 MIT 许可。这意味着即使你离开 Supabase,引擎和基于它编写的中间件仍可继续使用。它基于标准 Web Fetch API,可在任何支持 fetch 的运行时运行,如 Supabase Edge Functions、Vercel Functions、Cloudflare Workers、Deno、Bun 和 Node 22+。这种设计降低了供应商锁定的风险,让每请求逻辑真正成为可携带的资产。
类型安全与编译时检查的价值
defineMiddleware 提供类型安全的中间件定义,要求 TypeScript 5.4 或更高版本。类型参数能捕获重复的键、中间件顺序错误等常见问题,在编译阶段就发现错误。每请求逻辑中的错误容易上线且难以排查,类型检查能显著减少这类风险。对于纯 JavaScript 项目,运行时行为相同,但缺少这些编译时保障,开发者需自行注意顺序和键的唯一性。
运行时限制与替代方案
并非所有中间件都能在所有环境运行。withPostgresClient 和 withPostgresAdminClient 依赖 pg 库,需要 TCP socket,因此无法在 Cloudflare Workers 上使用。这是 pg 本身的限制,而非引擎的限制。在 Workers 上,应改用 withSupabaseClient 和 ctx.supabase 来获得调用者作用域的数据库访问。选择运行时前,需确认所需中间件的兼容性。
框架桥接与代码复用策略
在 Hono、H3、Elysia、NestJS、TanStack Start 等框架中使用时,需复制一个简短的桥接文件到项目,而非安装额外包。桥接文件将你编写的中间件数组适配到框架的中间件槽位,文件可自行编辑。这样,同一套认证和 CORS 规则可以同时用于纯 fetch 处理器和框架应用,避免为每个框架重写逻辑。桥接文件是唯一新增部分,中间件条目保持不变。
Q&A
Supabase Middleware 是什么?它主要解决什么问题?
Supabase Middleware 是 Supabase 发布的 @supabase/middleware 包,为 Web Fetch 处理器提供可组合、类型安全的中间件。它让开发者将每个请求的逻辑(如 CORS、JWT 验证、客户端注入)编写一次,即可在任意支持 fetch 的运行时及 Hono、NestJS 等框架中复用,避免逻辑散落在各个处理器中重复编写。
Supabase Middleware 内置了哪些中间件?它们分别有什么作用?
内置中间件包括:withCors 处理 CORS;withFeatureFlag 添加 ctx.featureFlag,标志开启时放行,否则返回 404;withClaims 添加 ctx.jwtClaims,无令牌时为 null,无效令牌返回 401;withRequiredClaims 验证 JWT 并添加 ctx.jwtClaims,无效则返回 401;withSupabaseClient 添加按调用者作用域的 Supabase 客户端;withSupabaseAdminClient 添加绕过 RLS 的服务角色客户端;withPostgresClient 添加应用 RLS 的 Postgres 连接;withPostgresAdminClient 添加绕过 RLS 的 Postgres 连接;withOAuthProtectedResource 处理 MCP 客户端的 OAuth 受保护资源元数据请求,并在 401 响应中添加 OAuth 挑战头。
Supabase Middleware 可以在哪些运行时和框架中使用?
它可以在任何支持 fetch 的运行时上运行,包括 Supabase Edge Functions、Vercel Functions、Cloudflare Workers、Deno、Bun 以及 Node 22 或更新版本。在框架方面,通过桥接文件可用于 Hono、H3、Elysia、NestJS 和 TanStack Start。注意 withPostgresClient 和 withPostgresAdminClient 因依赖 TCP 套接字,无法在 Cloudflare Workers 上运行。
如何在框架(如 Hono)中使用 Supabase Middleware?
需要将对应的桥接文件(如 hono/supabase-middleware.ts)复制到项目中,然后使用桥接函数(如 toHono)将中间件数组传入框架的中间件槽。例如在 Hono 中:app.use('*', toHono([withRequiredClaims(), withSupabaseClient()]))。桥接文件是项目的一部分,可自行编辑,只需安装 @supabase/middleware 包。
如何编写自定义中间件?
使用 defineMiddleware 函数,指定 key 和 run 函数。run 接收配置并返回处理每个请求的函数,该函数返回包含 key 的对象。类型参数依次为:key、配置、依赖的前置中间件提供的上下文、添加到 ctx 的内容。例如添加请求 ID 的中间件:const withRequestId = defineMiddleware<'requestId', void, Record<never, never>, string>({ key: 'requestId', run: () => async (req) => ({ requestId: req.headers.get('x-request-id') ?? crypto.randomUUID() }) })。类型检查需要 TypeScript 5.4 或更新版本。
Supabase Middleware 如何帮助构建 MCP 服务器?
使用 withOAuthProtectedResource 和 withSupabase({ auth: 'user' }) 两个中间件即可处理 MCP 服务器所需的 OAuth 受保护资源流程。withOAuthProtectedResource 处理 OAuth 发现元数据请求,并在 401 响应中添加挑战头;withSupabase 验证用户令牌并提供按用户作用域的客户端。这样每个工具调用都以该用户身份运行,RLS 策略自动生效,无需在每个工具中复制策略。
Supabase Middleware 是否绑定 Supabase?可以跨项目共享吗?
不绑定。引擎是纯 Web Fetch,不需要数据库、Supabase 项目或账户,采用 MIT 许可证,离开 Supabase 后引擎和编写的中间件仍可继续使用。中间件可以打包成 npm 包跨项目共享,例如 @supabase-labs/middleware-openfeature 就是一个独立包,只依赖引擎和 @openfeature/core。