# Edge Functions Edge Functions 用于服务端 Deno TypeScript 逻辑,如 API 端点、Webhook 处理、第三方集成等需要后端支持的场景。 ## 函数开发流程 1. **编写代码**:在 `/functions/{functionName}/index.ts` 中编写 Deno TypeScript 代码 2. **部署函数**:执行 `meoo-cli cloud deploy-function -n {functionName}` 命令部署函数 3. **重新部署**:每次代码修改后必须重新运行 deploy 命令 ## 函数结构 ```typescript Deno.serve(async (req) => { // CORS 预检 if (req.method === 'OPTIONS') { return new Response('ok', { headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', }, }); } const corsHeaders = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', }; try { const body = await req.json(); // 业务逻辑 return new Response(JSON.stringify({ data: body }), { headers: corsHeaders }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 400, headers: corsHeaders, }); } }); ``` ## 环境变量 **系统变量**(始终可用): - `SUPABASE_URL` — Supabase API URL(私有网络 URL) - `SUPABASE_ANON_KEY` — 公共匿名密钥 - `SUPABASE_SERVICE_ROLE_KEY` — 服务角色密钥(保密) - `SUPABASE_DB_URL` — PostgreSQL 连接 URL **自定义变量**:项目可能配置了额外的密钥。使用 `meoo-cli cloud list-functions` 查看完整的环境变量列表。 **重要**:只使用实际存在的环境变量,引用不存在的变量会导致运行时错误。 ## Supabase 客户端 ```typescript import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; // 管理员客户端(绕过 RLS) const supabaseAdmin = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!, ); // 用户客户端(遵守 RLS,使用前端 Auth header) const authHeader = req.headers.get('Authorization')!; const supabase = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!, { global: { headers: { Authorization: authHeader } } }, ); ``` ## 前端调用 **推荐使用 `fetch` 调用** — fetch 能提供完整的错误信息和更好的调试能力,非必要不建议使用 sdk invoke 调用。 **注意**:必须通过友好的 Toast 交互提醒用户数据操作结果,特别是操作失败的情况。 ```typescript import { supabase, getSupabaseUrl } from 'src/supabase/client.ts'; // 获取认证 headers const session = (await supabase.auth.getSession()).data.session; const authHeaders = session ? { Authorization: `Bearer ${session.access_token}` } : {}; // 基本函数调用 const response = await fetch(`${getSupabaseUrl()}/functions/v1/hello-world`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeaders }, body: JSON.stringify({ name: 'world' }), }); const result = await response.json(); if (!response.ok) { console.error('Function error:', result); } ``` > 使用 `fetch` 时,如果函数需要用户身份,**必须**手动附加 `Authorization` header。 ## 部署管理 1. **部署**:`meoo-cli cloud deploy-function -n {functionName}` 2. **删除**:`meoo-cli cloud delete-function -n {functionName}` > `/functions/{functionName}/` 下的代码修改是本地的,直到再次运行 deploy 命令才会更新在线函数。 # 适用场景 - 需要服务器端逻辑(如第三方 API 调用、密钥保护) - **浏览器真实 CORS 阻止前端 fetch/XHR 调用第三方或不可控外部 API,需要改为受限服务端代理** - API 端点 / Webhook 处理 - 定时任务 / 后台数据处理 - 需要使用 Service Role Key 绕过 RLS 的操作 ### 何时使用 Edge Function 做 CORS 代理 以下场景应使用 Edge Function 做受限服务端代理: - 预览中确认 CORS 错误来自前端 fetch/XHR 调用第三方或不可控外部 API - 用户要求 "把这个 API 调用移到后端,避免浏览器 CORS 拦截" - 用户要求 "用 Edge Function 代理这个外部 API,同时把 API key 留在后端" **不要** 为以下场景生成代理: - 静态资源 CDN(图片、字体、CSS)— 低价值,应直接用 `` 或 CSS - 脚本类 CDN(`cdn.jsdelivr.net`、`unpkg.com`)— 应用 `