You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Hono Cloudflare Workers中存储Supabase客户端的最佳方式

Hono + Cloudflare Worker 中 Supabase 客户端初始化最佳实践

核心疑问解答


1. 你提供的代码是否会为每个请求创建新的Supabase客户端?

是的。Hono的app.use('*')中间件会在每个请求到达时执行一次,且Hono的上下文c是每个请求独立生成的,不会在Worker实例间共享。因此每次请求都会调用createClient生成新的客户端实例,并绑定到当前请求的上下文中。

2. Cloudflare Workers中更高效的处理方式?

Cloudflare Workers存在「冷启动」和「热启动」机制:

  • 冷启动:Worker首次被触发时,模块级代码(全局作用域)会执行一次
  • 热启动:后续请求会复用已启动的Worker实例,模块级变量会被保留

由于@supabase/supabase-js的客户端是无状态、线程安全的(所有请求独立,不共享状态),可以将客户端实例放在模块全局作用域,冷启动时创建一次,后续热请求直接复用,大幅减少重复初始化的开销。

但如果你的场景需要为每个请求设置独立配置(比如用户JWT、自定义请求头),则仍需在中间件中为每个请求创建客户端,避免全局实例的配置被并发请求篡改。

3. Hono中共享数据库客户端的推荐模式

分两种场景选择:

场景一:无需每个请求自定义配置(固定服务端密钥)

将Supabase客户端实例放在模块全局作用域,通过中间件注入到Hono上下文,所有请求复用同一个实例:

import { Hono } from 'hono'
import { createClient } from '@supabase/supabase-js'

// 模块级全局实例,冷启动时仅创建一次
const supabaseGlobal = createClient(
  'SUPABASE_URL',
  'SUPABASE_KEY'
)

type Variables = {
  supabase: SupabaseClient
}

const app = new Hono<{ Variables: Variables }>()

// 中间件将全局实例注入上下文
app.use('*', async (c, next) => {
  c.set('supabase', supabaseGlobal)
  await next()
})

// 路由中直接使用
app.get('/api/data', async (c) => {
  const supabase = c.get('supabase')
  const { data, error } = await supabase.from('your_table').select('*')
  if (error) return c.json({ error: error.message }, 500)
  return c.json(data)
})
场景二:需要每个请求自定义配置(如用户授权)

在中间件中为每个请求创建独立的客户端实例,注入专属配置(比如从请求头获取用户JWT):

import { Hono } from 'hono'
import { createClient } from '@supabase/supabase-js'

type Variables = {
  supabase: SupabaseClient
}

const app = new Hono<{ Variables: Variables }>()

app.use('*', async (c, next) => {
  // 从请求头提取用户授权Token
  const authToken = c.req.header('Authorization')?.replace('Bearer ', '')
  
  // 为当前请求创建带专属配置的客户端
  const supabase = createClient(
    'SUPABASE_URL',
    'SUPABASE_KEY',
    {
      global: {
        headers: {
          Authorization: authToken ? `Bearer ${authToken}` : ''
        }
      }
    }
  )
  
  c.set('supabase', supabase)
  await next()
})

app.get('/api/user-data', async (c) => {
  const supabase = c.get('supabase')
  const { data, error } = await supabase.from('user_data').select('*').eq('user_id', 'current_user_id')
  if (error) return c.json({ error: error.message }, 401)
  return c.json(data)
})

补充说明

  • Hono上下文的生命周期:每个请求会生成独立的上下文实例,上下文内的变量仅对当前请求有效,不会跨请求共享。
  • 全局实例的安全前提:Supabase客户端无状态,请求间不会互相干扰,因此全局复用是安全的;若客户端存在状态性属性(如全局auth),则必须避免全局复用。

内容的提问来源于stack exchange,提问作者bulut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:28:24