文档 / 搜索 / LingCode Cloud / 函数
📘 参考 ● 函数 更新于 2026-06-11

函数

一句话:函数是你按 slug 调用的服务端代码。分两类:七个内置函数,它们已经在每个后端上线——设置好所需密钥后直接调用,无需部署;以及你用 TypeScript 编写、在 Deno 沙箱运行时里运行的自定义函数。两类都用 lingcode.functions.invoke(slug, body?) 调用,或者向 /api/cloud/be/<backend-id>/functions/<slug> 发 POST 请求。用函数去做浏览器无法安全完成的事:持有密钥、调用厂商 API、运行受信任的逻辑。

函数存在只有一个理由:有些事浏览器没法安全地做。它不能持有 Stripe secret key。它不能被信任去计算价格或授予访问权限。它不能调用一个需要凭证的厂商 API。函数就是你应用里那一小块在服务端、在你的后端背后运行的部分——在那里,密钥仍然是密钥。本页同时覆盖两种形态:开箱即用的内置函数,以及你自己编写的自定义函数,以及怎么调用它们。

函数为什么存在

客户端 SDK 里的一切——from('table').select()、认证、存储——都用公开的 anon key(匿名密钥)对一层轻量网关发起调用,由行级安全负责守门。这覆盖了一个应用的大部分。但有些逻辑必须活在用户看不到、也改不了的地方:

你通过slug——一个短名字——来访问函数。拿到 slug 有两条路:用内置函数(已经上线,只需设置好它的密钥),或者写一个自定义函数(你自己的 TypeScript)。两者的调用方式完全相同。

如何调用(两类通用)

在 SDK 里,用 slug 和一个可选的 body 调用 functions.invoke。和每个 SDK 调用一样,它返回一个 Result——{ data, error }——所以你永远不必把它包进 try/catch:

const { data, error } = await lingcode.functions.invoke('echo', {
  hello: 'world'
});
// data -> { hello: 'world', timestamp: '2026-06-11T…' }

或者通过 REST 调用——从服务器、curl 烟雾测试或非 JS 客户端发起时很方便。向函数端点 POST 一个 { input } body,由 anon key 或已登录用户的令牌授权:

POST https://lingcode.dev/api/cloud/be/<backend-id>/functions/<slug>
Authorization: Bearer <anon-key-or-user-token>
Content-Type: application/json

{ "input": { "hello": "world" } }

unknown_function 表示名字写错了

如果一次调用返回 unknown_function,说明 slug 拼错了,或者这个后端上不存在该函数——它表示函数功能不可用。对照下面的内置函数检查 slug,或对照你给自定义函数起的 slug。(关于运行时本身宕机的那唯一一种情况,见可用性——它以 503 functions_runtime_unavailable 的形式出现,且仅针对自定义函数。)

七个内置函数

这些在每个后端上都已上线,没有部署步骤。对每一个,你只需在密钥保险库里设置它所需的密钥(如果有),然后按 slug 调用。先从 echo 开始,确认你的接线没问题。

Slug作用输入所需密钥
echo 原样返回你的输入,外加一个时间戳。用它来烟雾测试 invoke 是否正常。 任意内容
send-email 通过 LingCode 的托管发件方发送邮件。 { to, subject, html }
elevenlabs-tts 文本转语音。返回 base64 音频。 { text, voice_id?, model_id? }{ audio_base64, content_type } ELEVENLABS_API_KEY
twilio-sms 通过 Twilio 发送短信。 { to, body, from?, messaging_service_sid? } TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKEN,外加 TWILIO_FROMTWILIO_MESSAGING_SERVICE_SID 二者之一
resend-byo 通过你自己的 Resend 账户发送邮件。 { from, to, subject, html?, text? } RESEND_API_KEY
stripe-checkout 创建一个 Stripe Checkout Session。 { price_id, success_url, cancel_url, mode?, quantity?, customer_email?, metadata? }{ id, url } STRIPE_SECRET_KEY
http-fetch 向白名单内的主机发起一次出站 HTTPS 请求。 { url, method?, headers?, body? } 自身无需密钥——但 header/body 字符串可以用 {{SECRET_NAME}} 引用保险库里的密钥

echo 做烟雾测试

新后端上最该先跑的东西。如果它把你的输入原样返回,说明 invoke 已接通,你的 URL + key 也都正确。

const { data } = await lingcode.functions.invoke('echo', { ping: 1 });
console.log(data); // { ping: 1, timestamp: '2026-06-11T…' }

创建一个 Stripe Checkout Session

先在密钥保险库里设置 STRIPE_SECRET_KEY——它永远不会碰到浏览器。然后调用这个内置函数,把用户重定向到返回的 URL:

const { data, error } = await lingcode.functions.invoke('stripe-checkout', {
  price_id:    'price_123',
  success_url: 'https://yourapp.com/thanks',
  cancel_url:  'https://yourapp.com/pricing',
  mode:        'subscription'
});
if (error) throw error;
window.location.href = data.url; // 托管的 Stripe Checkout

http-fetch:感知密钥、限定主机

http-fetch 自身没有密钥,但 header 或 body 字符串里任意 {{SECRET_NAME}} 标记都会在服务端从保险库里替换进来——这样你就能调用一个需要 bearer token 的 API,而 token 从不抵达客户端。目标主机必须在后端的 fetch-hosts 白名单里;对不在名单上的主机的调用会被拒绝。这是不写任何代码就能调用第三方 API 的、刻意收紧的方式。参见教程从后端调用外部 API

自定义函数

当没有内置函数合适时,就写你自己的。你在 Cloud 控制台 / IDE 里编写自定义函数——给函数一个 slug 和它的 TypeScript 源码(这是控制台里的一步编写动作,不是 agent 工具替你完成的事)。它们在 Deno 沙箱运行时里运行,用和内置函数同一个 functions.invoke(slug, body?) 调用来触发。

约定

你的源码必须 export default 一个 handler。你 return 的东西就成为调用结果的 data。原生支持 TypeScript——Deno 直接运行,无需构建步骤:

export default async function handler(input, ctx) {
  // ctx.secrets.MY_KEY  — 你的保险库密钥,仅服务端可见
  // ctx.backendId       — 这个后端的 id
  // ctx.gateway         — 这个后端自己的 data-API 基础 URL
  return { ok: true };   // 成为调用结果的 `data`
}

第二个参数 ctx 是你的服务端上下文:

ctx = {
  secrets:   { /* 保险库里设置的每一个密钥,按名字 */ },
  backendId: string,
  gateway:   string   // 通过它调用你自己的 data API
}

一个小小的自定义函数

从保险库读取一个密钥并返回 JSON。密钥从不离开服务端:

export default async function handler(input, ctx) {
  const key = ctx.secrets.WEATHER_API_KEY;
  const city = input.city ?? 'NYC';
  const res = await fetch(
    `https://api.example.com/weather?city=${city}&key=${key}`
  );
  const json = await res.json();
  return { city, tempC: json.temp_c };
}

从客户端调用它,和内置函数完全一样——按它的 slug:

const { data, error } = await lingcode.functions.invoke('get-weather', {
  city: 'Tokyo'
});
if (error) throw error;
console.log(data.tempC);

沙箱

自定义函数在 Deno 里运行,权限默认全部拒绝。这是一个特性,不是要去对抗的限制:

限制

限制freepromax_pro
超时(墙钟时间,超过即 SIGKILL)3s10s30s
自定义函数数量(maxFunctions21050
源码体积最多 256 KB
内存128 MB

函数是短命的。超过墙钟超时后,进程会被 SIGKILL——没有优雅的延长机制。不要把任何运行超过约 30 秒的东西放进函数。

可用性

自定义函数需要 Deno 运行时,而它已经在生产环境安装并上线——自定义函数现在就能用。如果某次部署确实缺少运行时,自定义调用会返回 503 functions_runtime_unavailable,而内置函数照常工作(它们不依赖 Deno 沙箱)。所以自定义函数上的 503 是一个运行时可用性信号;内置函数失败则是另一回事。还要记住——unknown_function 永远是 slug 写错的错误,从不表示可用性问题。

函数不适合做什么。没有长时间运行的进程、没有后台队列、没有常驻的 WebSocket 服务器,也没有任何超过约 30 秒的东西——那些都属于托管的 Worker 应用,不属于函数。一个诚实的具体例子:一个需要原始请求体签名校验的 Stripe webhook 处理器不是这些内置函数之一,而且很难用一个短小的自定义函数来表达——把它放进你托管应用自己的路由(Worker/SSR 路由)里。stripe-checkout 内置函数只创建 Checkout Session;它不接收 webhook。