Supabase 中间件:面向 Web Fetch 处理器的可组合、可复用中间件

Supabase 中间件:面向 Web Fetch 处理器的可组合、可复用中间件

💡 原文英文,约2000词,阅读约需8分钟。
📝

内容提要

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。

🏷️

标签

➡️

继续阅读