Supabase Edge Functions本地开发 #

一、本地环境配置 #

1.1 安装依赖 #

bash
# 确保已安装Supabase CLI
supabase --version

# 登录
supabase login

1.2 初始化项目 #

bash
# 初始化
supabase init

# 链接远程项目
supabase link --project-ref your-project-ref

1.3 启动本地服务 #

bash
# 启动所有服务
supabase start

# 输出
API URL: http://localhost:54321
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
Studio URL: http://localhost:54323
Inbucket URL: http://localhost:54324
anon key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
service_role key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

二、函数开发 #

2.1 创建函数 #

bash
supabase functions new my-function

2.2 目录结构 #

text
supabase/
├── functions/
│   ├── my-function/
│   │   └── index.ts
│   ├── another-function/
│   │   └── index.ts
│   └── _shared/
│       ├── supabase.ts
│       └── utils.ts
├── migrations/
├── config.toml
└── .env

2.3 共享代码 #

typescript
// functions/_shared/supabase.ts
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'

export function createSupabaseClient(authToken?: string) {
  return createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
    {
      global: authToken ? {
        headers: { Authorization: `Bearer ${authToken}` },
      } : undefined,
    }
  )
}
typescript
// functions/my-function/index.ts
import { createSupabaseClient } from '../_shared/supabase.ts'

Deno.serve(async (req) => {
  const authHeader = req.headers.get('Authorization')
  const token = authHeader?.replace('Bearer ', '')
  
  const supabase = createSupabaseClient(token)
  
  // 使用supabase客户端...
})

三、本地测试 #

3.1 启动函数服务 #

bash
# 启动函数服务
supabase functions serve

# 指定环境变量文件
supabase functions serve --env-file .env.local

3.2 测试请求 #

bash
# GET请求
curl http://localhost:54321/functions/v1/my-function \
  -H "Authorization: Bearer YOUR_ANON_KEY"

# POST请求
curl -X POST http://localhost:54321/functions/v1/my-function \
  -H "Authorization: Bearer YOUR_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "test"}'

# 带自定义头
curl http://localhost:54321/functions/v1/my-function \
  -H "Authorization: Bearer YOUR_ANON_KEY" \
  -H "X-Custom-Header: value"

3.3 测试脚本 #

typescript
// test.ts
const SUPABASE_URL = 'http://localhost:54321'
const ANON_KEY = 'your-anon-key'

async function testFunction() {
  const response = await fetch(`${SUPABASE_URL}/functions/v1/my-function`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${ANON_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ name: 'Test' }),
  })

  const data = await response.json()
  console.log('Response:', data)
}

testFunction()
bash
# 运行测试
deno run --allow-net test.ts

四、环境变量 #

4.1 本地环境变量 #

bash
# supabase/.env
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
MY_API_KEY=your-api-key

4.2 使用环境变量 #

typescript
Deno.serve(async (req) => {
  const apiKey = Deno.env.get('MY_API_KEY')
  
  if (!apiKey) {
    console.error('MY_API_KEY not set')
    return new Response('Configuration error', { status: 500 })
  }
  
  // 使用apiKey...
})

4.3 不同环境配置 #

bash
# 开发环境
.env.development

# 生产环境
.env.production

# 使用指定环境
supabase functions serve --env-file .env.development

五、调试技巧 #

5.1 控制台日志 #

typescript
Deno.serve(async (req) => {
  console.log('=== Request Start ===')
  console.log('Time:', new Date().toISOString())
  console.log('Method:', req.method)
  console.log('URL:', req.url)
  
  const body = await req.text()
  console.log('Body:', body)
  
  try {
    const json = JSON.parse(body)
    console.log('Parsed JSON:', json)
  } catch (e) {
    console.log('Not JSON body')
  }
  
  // 处理逻辑...
  
  console.log('=== Request End ===')
  
  return new Response('OK')
})

5.2 错误追踪 #

typescript
Deno.serve(async (req) => {
  try {
    // 处理逻辑
    const result = await riskyOperation()
    return new Response(JSON.stringify(result))
  } catch (error) {
    console.error('Error occurred:', error)
    console.error('Stack:', error.stack)
    
    return new Response(
      JSON.stringify({
        error: error.message,
        stack: Deno.env.get('ENVIRONMENT') === 'development' ? error.stack : undefined,
      }),
      { status: 500, headers: { 'Content-Type': 'application/json' } }
    )
  }
})

5.3 性能监控 #

typescript
Deno.serve(async (req) => {
  const startTime = performance.now()
  
  // 处理逻辑
  const result = await processRequest()
  
  const endTime = performance.now()
  const duration = endTime - startTime
  
  console.log(`Request took ${duration.toFixed(2)}ms`)
  
  return new Response(JSON.stringify(result))
})

六、VS Code配置 #

6.1 Deno扩展 #

text
安装扩展
├── Deno (denoland.vscode-deno)
└── 配置Deno为默认TypeScript服务器

6.2 settings.json #

json
{
  "deno.enable": true,
  "deno.lint": true,
  "deno.unstable": true,
  "deno.importMap": "./supabase/functions/import_map.json"
}

6.3 import_map.json #

json
{
  "imports": {
    "@supabase/supabase-js": "https://esm.sh/@supabase/supabase-js@2",
    "std/": "https://deno.land/std@0.208.0/"
  }
}

七、常见问题 #

7.1 端口冲突 #

bash
# 检查端口占用
lsof -i :54321

# 修改端口
supabase functions serve --port 54322

7.2 热重载不生效 #

bash
# 重启服务
supabase functions serve --no-verify-jwt

7.3 环境变量不加载 #

bash
# 确保在正确目录
cd supabase

# 显式指定环境文件
supabase functions serve --env-file .env

八、最佳实践 #

8.1 代码组织 #

typescript
// 分离逻辑
// functions/_shared/handlers.ts
export async function handleGet(req: Request) {
  // GET处理逻辑
}

export async function handlePost(req: Request) {
  // POST处理逻辑
}
typescript
// functions/my-function/index.ts
import { handleGet, handlePost } from '../_shared/handlers.ts'

Deno.serve(async (req) => {
  switch (req.method) {
    case 'GET':
      return handleGet(req)
    case 'POST':
      return handlePost(req)
    default:
      return new Response('Method not allowed', { status: 405 })
  }
})

8.2 类型定义 #

typescript
// functions/_shared/types.ts
export interface User {
  id: string
  email: string
  name: string
}

export interface ApiResponse<T> {
  success: boolean
  data?: T
  error?: string
}

九、总结 #

本地开发要点:

操作 命令
启动服务 supabase functions serve
测试请求 curl localhost:54321/functions/v1/name
查看日志 控制台输出
环境变量 –env-file .env

下一步,让我们学习函数调用!

最后更新:2026-03-28