Cloudflare Workers中Better Auth与Supabase连接问题排查
在Cloudflare Workers中连接Better Auth与Supabase PostgreSQL的问题
背景
- 运行环境:Cloudflare Workers
- 数据库:Supabase(带事务池的PostgreSQL)
- 测试的ORM/客户端:
postgres.js、kysely - 认证库:Better Auth
问题
- 使用Supabase事务池(pgBouncer)→ 间歇性可用(约50%失败率)
- 使用
postgres.js或kysely→ 在Cloudflare Workers中经常被阻断 - 问题疑似与Workers的TCP连接限制相关
尝试的解决方案
尝试方案1:使用PgPool
PgPool连接配置
import { Pool } from "pg"; import "dotenv/config"; const connectionString = process.env.DATABASE_URL; if (!connectionString) { throw new Error ("❌ 数据库URL未定义,请检查.env文件。") } export const database = new Pool ({ connectionString, max: 10, //ssl: { rejectUnauthorized: false } });
搭配PgPool的Better Auth配置
import { betterAuth } from "better-auth"; import {database} from "./db.connect.ts"; import "dotenv/config"; export const auth = betterAuth({ // database: database, secret: process.env.BETTER_AUTH_SECRET, trustedOrigins: [ process.env.BETTER_AUTH_URL!, ], // 其余配置 });
✅ 偶尔可用
❌ 随机失败(约每2次请求失败1次)
尝试方案2:直接适配器(无异步)
Kysely连接配置
import { Kysely } from "kysely"; import { PostgresJSDialect } from "kysely-postgres-js"; import postgres from "postgres"; const connectionString = process.env.DATABASE_URL!; export const kysely = new Kysely<any>({ dialect: new PostgresJSDialect({ postgres: postgres(connectionString) }), });
搭配Kysely的Better Auth配置
import { betterAuth } from "better-auth"; import {kysely} from "./kysely.ts"; import { kyselyAdapter } from "@better-auth/kysely-adapter"; import "dotenv/config"; export const auth = betterAuth({ database: kyselyAdapter (kysely), secret: process.env.BETTER_AUTH_SECRET, trustedOrigins: [ process.env.BETTER_AUTH_URL!, ], // 其余配置 });
从第二次请求开始,Wrangler返回错误:
Error: Cannot perform I/O on behalf of a different request. I/O objects (such as streams, request/response bodies, and others) created in the context of one request handler cannot be accessed from a different request's handler. This is a limitation of Cloudflare Workers which allows us to improve overall performance. (I/O type: Writable)
尝试方案3:动态适配器
Kysely连接配置
import { Kysely } from "kysely"; import { PostgresJSDialect } from "kysely-postgres-js"; import postgres from "postgres"; const connectionString = process.env.DATABASE_URL!; export function createKysely () { return new Kysely<any>({ dialect: new PostgresJSDialect({ postgres: postgres(connectionString) }), }); }
搭配Kysely的Better Auth配置
import { betterAuth } from "better-auth"; import {createKysely} from "./kysely.ts"; import { kyselyAdapter } from "@better-auth/kysely-adapter"; import "dotenv/config"; export const auth = betterAuth({ database : kyselyAdapter (createKysely()) secret: process.env.BETTER_AUTH_SECRET, trustedOrigins: [ process.env.BETTER_AUTH_URL!, ], // 其余配置 });
我还尝试了:
database: {async get() { return kyselyAdapter (createKysely()) } },
仍返回相同错误。
猜想
Cloudflare Workers可能:
- 无法妥善支持原生TCP连接
- 无法可靠支持连接池(pg/pgBouncer)
- 需要基于HTTP的数据库驱动
核心问题
- Cloudflare Workers是否支持TCP方式的postgres.js/Kysely?
- Supabase pgBouncer能否在边缘无服务器环境可靠运行?
- Workers中Better Auth搭配Supabase的推荐架构是什么?
是否应选择:
- 使用Supabase HTTP API而非直接数据库访问?
- 添加Node.js后端作为代理?
- 切换至Neon HTTP驱动等无服务器Postgres驱动?
解答
1. Cloudflare Workers对TCP方式postgres.js/Kysely的支持
Cloudflare Workers有限支持原生TCP连接,但存在严格限制:
- Workers的运行环境是无状态边缘容器,每个请求的执行上下文完全隔离,跨请求复用TCP连接会触发「跨请求I/O访问」错误。
postgres.js和Kysely默认的TCP驱动依赖长连接,而Workers的连接数配额极低,且连接会在请求结束后被强制回收,导致连接池失效、请求频繁失败。
2. Supabase pgBouncer在边缘环境的可靠性
Supabase的pgBouncer事务池不适合直接在Cloudflare Workers中使用:
- pgBouncer依赖长连接复用,但Workers的短生命周期和上下文隔离特性会频繁断开连接,导致连接池命中率极低,出现你看到的50%失败率。
- 边缘环境与Supabase集群的网络延迟波动,会进一步加剧连接不稳定问题。
3. Workers中Better Auth搭配Supabase的推荐架构
优先方案:使用Supabase HTTP API替代直接数据库访问
直接通过Supabase提供的REST/GraphQL API操作数据库,完全适配Workers的边缘环境:
- 无需维护TCP连接,所有请求通过HTTP完成,规避Workers的I/O限制。
- Better Auth可以通过自定义适配器,调用Supabase API完成用户数据的读写操作。
示例简化配置思路:
import { betterAuth } from "better-auth"; import { createClient } from '@supabase/supabase-js'; const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!); export const auth = betterAuth({ database: { // 实现Better Auth所需的数据库操作方法,内部调用Supabase API async createUser(user) { const { data, error } = await supabase.from('users').insert(user).select().single(); if (error) throw error; return data; }, // 其他必要方法(getUser, updateUser等) }, secret: process.env.BETTER_AUTH_SECRET, trustedOrigins: [process.env.BETTER_AUTH_URL!], // 其余配置 });
备选方案:使用基于HTTP的Postgres驱动
如果一定要直接操作数据库,替换为支持HTTP协议的Postgres驱动(如Neon的@neondatabase/serverless):
- 该驱动通过HTTP/HTTPS发送SQL请求,完全兼容Workers的环境,无需TCP连接。
- 适配Kysely的话,使用
@neondatabase/serverless作为dialect:
import { Kysely } from "kysely"; import { NeonDialect } from "kysely-neon"; import { neon } from '@neondatabase/serverless'; const connectionString = process.env.DATABASE_URL!; export const kysely = new Kysely<any>({ dialect: new NeonDialect({ pool: { connectionString, }, }), });
然后将此Kysely实例传入Better Auth的适配器即可,注意要确保驱动版本与Better Auth适配器兼容。
不推荐方案:添加Node.js后端代理
这种方式会增加架构复杂度和延迟,违背使用Cloudflare Workers的边缘优势,除非有特殊业务需求,否则不建议采用。
内容的提问来源于stack exchange,提问作者Nazim M.
相关产品推荐
相关产品推荐

