一句话:函数是你按 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_SID、TWILIO_AUTH_TOKEN,外加 TWILIO_FROM 或 TWILIO_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_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 里运行,权限默认全部拒绝。这是一个特性,不是要去对抗的限制:
ctx.gateway)。函数可以调用你的 data API——但它没法把数据外泄到任意主机。(需要触达某个厂商?用 http-fetch 内置函数的白名单,或者让你的函数绕回网关来发起。)| 限制 | free | pro | max_pro |
|---|---|---|---|
| 超时(墙钟时间,超过即 SIGKILL) | 3s | 10s | 30s |
自定义函数数量(maxFunctions) | 2 | 10 | 50 |
| 源码体积 | 最多 256 KB | ||
| 内存 | 128 MB | ||
函数是短命的。超过墙钟超时后,进程会被 SIGKILL——没有优雅的延长机制。不要把任何运行超过约 30 秒的东西放进函数。
自定义函数需要 Deno 运行时,而它已经在生产环境安装并上线——自定义函数现在就能用。如果某次部署确实缺少运行时,自定义调用会返回 503 functions_runtime_unavailable,而内置函数照常工作(它们不依赖 Deno 沙箱)。所以自定义函数上的 503 是一个运行时可用性信号;内置函数失败则是另一回事。还要记住——unknown_function 永远是 slug 写错的错误,从不表示可用性问题。
stripe-checkout 内置函数只创建 Checkout Session;它不接收 webhook。