Cloud Function API
Cloud Function API 是一个无服务器云函数服务,允许第三方应用通过 HTTP 请求调用预先编写的 JavaScript 函数。你可以在管理面板中创建和编辑云函数,然后通过 API 调用执行它们。
概览
| 项目 | 说明 |
|---|---|
| 基础路径 | /cf/api/ |
| 认证方式 | Basic(应用模式)或 Bearer(用户模式) |
| 数据格式 | JSON |
| 函数数量额度 | 默认每个应用 50 个;应用所有者可申请提高至最多 10,000 个 |
| 代码大小上限 | 256 KB |
| 超时时间 | 5,000 ~ 30,000 ms |
| 内存限制 | 64 MB |
| 返回值上限 | 1 MB |
认证
普通 /cf/api/{folder}/{name} 始终是带认证入口,即使目标函数配置了 requireAuth=0 也必须提供 Authorization。匿名调用请明确使用以下入口之一:
- Wrapped JSON:
/cf/api/public/{clientId}/{folder}/{name} - Raw HTTP / 网站下载 / Webhook:
/cf/http/public/{clientId}/{folder}/{name}
requireAuth=0 只表示函数允许匿名身份执行,不会把普通带认证 URL 隐式降级为公开 URL。
Cloud Function API 支持两种认证模式,通过 Authorization 请求头区分:
应用模式(Basic)
使用应用的 client_id 和 client_secret 进行认证。
Authorization: Basic base64(client_id:client_secret)⚠️ 安全提示:
client_secret拥有应用的完整管理权限。绝对不要将其写入分发给用户的客户端程序。应用模式仅应在受信任的服务器环境或内部开发工具中使用。推荐架构:面向用户的客户端应使用 Bearer 模式(用户 OIDC 登录)调用云函数,在云函数内通过
caller+$permission验证用户身份和权限,通过$data读写数据。这是最安全的集成方式。
用户模式(Bearer)
使用用户的 OAuth access_token 进行认证。云函数内可以通过 caller 对象获取调用者信息。
Authorization: Bearer <access_token>重放防护
带认证的 /cf/api/... 请求必须携带以下请求头以防止重放攻击。公开端点 /cf/api/public/... 和 Raw HTTP 端点 /cf/http/public/... 不要求这些请求头。
| 请求头 | 说明 |
|---|---|
X-Timestamp | 当前 Unix 时间戳(秒),与服务器时差不超过 ±5 分钟 |
X-Nonce | 随机唯一字符串,16~64 个字母数字字符,每次请求不同 |
X-Timestamp: 1719000000
X-Nonce: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6核心概念
函数数量额度与扩容
应用默认可创建 50 个云函数。管理页和以下管理接口会返回 functionQuota,其中包含 used、limit、remaining、maximumLimit 与最近一次申请状态:
GET /cf/manage/{clientId}/overview
GET /cf/manage/{clientId}/functions应用所有者可提交扩容申请;提高额度需管理员审核,批准值可低于申请值,但必须高于当前额度:
POST /oauth/apps/{clientId}/cloud-function-limit/request
Authorization: Bearer <owner_access_token>
Content-Type: application/json
{
"requestedLimit": 100,
"reason": "正式环境将按业务域拆分下载、支付和通知函数"
}创建函数和额度审批使用同一应用级互斥锁,避免并发创建越过生效额度。扩容申请复用平台 服务申请与管理员审核流程,不要求开发者直接联系 R2 或修改服务器配置。
云函数(Cloud Function)
云函数是一段在沙盒环境中执行的 JavaScript 代码。每个云函数有以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
name | string | 函数名称,在应用内唯一,只允许字母、数字、下划线 |
description | string | 函数描述 |
folder | string | null | 文件夹路径,用于组织函数 |
timeout | number | 超时时间(ms),范围 5,000 ~ 30,000;支付等网络密集函数可配置 30 秒 |
enabled | number | 是否启用(1 = 启用) |
requireAuth | number | 是否需要身份验证(1 = 需要,默认;0 = 匿名公开) |
invokeAccess | string | 调用入口:http(默认,允许 HTTP/API 和 $invoke)或 cloud_function(仅允许 $invoke) |
invokeMethod | string | HTTP 调用方式:post(默认)、get、both |
outputMode | string | API 端点响应结构:default(默认)、direct、mixed |
requestMode | string | 输入协议:wrapped(默认 { params })或显式 raw(第三方 Webhook) |
rawHttpUrl | string | null | 管理 API 生成的 Raw 公开 URL;仅 requestMode=raw 时返回 |
configVars | object | 可读回的普通配置,适合 URL、开关、Bundle ID 等非敏感内容;通过 env 访问 |
configVarsSource | string | 普通配置的 JSONC 源文本,保留 //、/* */ 注释和尾随逗号 |
envVars | object | 兼容入口,现为只写函数级 Secret;读取时仅返回 __STARECHO_SECRET_SET__ 占位符 |
invokeAccess = cloud_function 适合把函数作为私有 helper 使用。该模式下,用户、匿名访问、 Basic/Bearer HTTP 请求和定时任务都不能直接调用该函数;只有其他云函数内的 $invoke 可以调用它。
只写 Secret Store
应用级 Secret 与单个函数解耦,适合 Apple .p8、API Key、Webhook Secret 和 OAuth Client Secret。管理接口永不返回值,只返回名称、isSet 和时间戳:
GET /cf/manage/{clientId}/secrets
PUT /cf/manage/{clientId}/secrets/{NAME} # body: { "value": "..." }
DELETE /cf/manage/{clientId}/secrets/{NAME}管理面板的 Secret 值编辑器支持多行输入,可直接粘贴 PEM、.p8 等私钥;输入内容 默认遮罩,换行会随值原样提交并加密保存。Secret 保存成功后输入框会立即清空,管理端 不能再次读回明文。
PUT 的响应会立即脱敏。应用级和函数级 Secret 都允许保存空字符串,表示 Key 已登记、值仍 待手动配置;此时 isSet=false,$secrets.has(NAME) 返回 false,$secrets.ref(NAME) 会明确 报“尚未配置”。__STARECHO_SECRET_SET__ 占位符仍表示保留已有函数级 Secret。应用级 Secret 使用上面的 DELETE,函数级兼容 Secret 则在更新函数时通过 deleteEnvVars: ['NAME'] 显式删除。运行时为向后兼容仍可通过 env.NAME 读取, 新的签名/托管 API 应使用 $secrets.ref('NAME'),避免把值交给业务代码。控制台日志、错误和 持久化执行记录会自动屏蔽已配置的 Secret 值。云函数的 HTTP/函数调用返回值保持原样, 以免破坏预签名 URL、Webhook 签名、密文和不透明 token;因此业务代码不得显式返回 Secret 值。
仅 Key 的备份与恢复
选择“云函数”导出时,请求只需要选择服务:
POST /backup/manage/{clientId}/export
Content-Type: application/json
{
"services": ["cloud_function"]
}新版备份只把应用级 Secret Store 和旧函数级 envVars 的名称写入 cloud-function/secret-keys.json,绝不把实际值写入备份。恢复时平台会按清单创建空值 Key, 并在校验结果及恢复响应的 requiredSecretConfiguration 中分别列出需要手动补录的应用级和 函数级 Secret。管理面板会在导入前后显示该清单。
平台继续兼容旧版 v2 cloud-function/secrets.enc.json 导入:只有这种旧备份仍需要通过 multipart secretsPassphrase 提供原口令。v1 备份不含 Secret 快照,恢复时保留目标应用当前 的应用级 Secret Store。
定时规则(Cron Rules)
定时规则用于周期性触发云函数。规则由管理接口维护:
GET /cf/manage/{clientId}/cron
POST /cf/manage/{clientId}/cron
PUT /cf/manage/{clientId}/cron/{ruleId}
DELETE /cf/manage/{clientId}/cron/{ruleId}创建或更新规则时常用字段:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 可选,定时规则显示名称 |
functionUid | string | 主目标云函数 UID |
cronExpr | string | 5 段 cron 表达式:分 时 日 月 周 |
scheduleType | string | cron、workday、holiday、festival |
scheduleConfig | string | 可视化调度配置 JSON 字符串,用于多时间点、节日等场景 |
functionTargets | string | 可选,多目标函数 UID JSON 数组;为空时只执行 functionUid |
timeZone | string | IANA 时区,例如 Asia/Shanghai、UTC |
params | object | 定时触发时合并传入云函数的 JSON 参数 |
maxExecutions | number | 最大执行次数,0 或空表示不限制 |
enabled | number | 更新时可设置,1 启用、0 禁用 |
定时触发时,云函数以应用身份运行,params 会先合并规则中的自定义参数,再覆盖写入系统字段:
{
...ruleParams,
__trigger: 'cron',
ruleId,
cronExpr,
scheduleType,
timeZone
}PM2 多实例或 cluster 部署下,平台会用 MySQL 分布式锁和分钟级执行桶去重。同一条规则在同一分钟只会实际执行一次,避免多实例重复触发。
沙盒环境
云函数在隔离的 Node.js Worker 沙盒中执行,具有以下特性:
- 安全隔离:每次执行在独立的 VM 上下文中运行,内存上限 64 MB
- 超时控制:函数执行超过设定时间后将被终止
- Console 捕获:
console.log/warn/error/info输出会被记录到执行日志(最多 100 条) - 无文件系统访问:不能访问宿主机的文件系统
- 受控网络访问:通过内置
fetch()可发起 HTTP/HTTPS 请求(禁止访问内网地址) - 并发限制:每个应用最多同时运行 5 个云函数实例
函数上下文
你的函数代码可以访问以下全局变量和内置 API:
| 变量 | 类型 | 说明 |
|---|---|---|
params | object | 调用方传入的参数(只读) |
env | object | 合并后的普通配置和 Secret(只读,保留既有 env.KEY 行为) |
caller | object | 调用者信息(只读) |
caller.mode | string | "user"、"app" 或 "anonymous" |
caller.uid | string | undefined | 用户 uid(仅 user 模式存在) |
request | object | Raw HTTP 入口专用的原始请求上下文;普通 /cf/api/... 调用为空对象 |
console | object | 日志输出(log, warn, error, info) |
$data | object | 数据合集内置 API,支持原子操作、排序、条件过滤 |
$permission | object | 权限组内置 API |
$account | object | 账号内置 API,用于查询用户最小信息和头像时效链接 |
$storage | object | 文件存储内置 API,支持上传、下载、删除、列表 |
$crypto | object | 加密内置 API,支持 AES-256-GCM、hash、HMAC、ES256 JWS |
$certificates | object | JWS/X.509 发布策略,只允许固定引用当前应用的已发布版本 |
$secrets | object | 只写 Secret 引用,管理端无法读回 Secret 值 |
$appleIap | object | Apple IAP 托管 API,支持 API Token 与服务端交易查询 |
$invoke | function | 函数互调,可调用同应用或通过 withBasic 跨应用调用云函数 |
fetch | function | HTTP 请求,仅限公网地址 |
btoa / atob | function | Base64 编解码 |
还包括标准 JavaScript 内建对象:JSON, Math, Date, Promise, Map, Set, RegExp, URL, Array, Object, String, Number, Boolean, Error 等。
以下内容被禁止访问:setTimeout, setInterval, process, require, Buffer, global, globalThis, __dirname, __filename。
编写方式
⚠️ 重要:不需要定义
function main()或任何入口函数。你的代码会被自动包裹在async立即执行函数中,直接编写业务逻辑即可,可以直接使用await和return。
// ✅ 正确写法:直接编写代码
const name = params.name || 'World'
return { message: `Hello, ${name}!` }
// ❌ 错误写法:不要定义 main 函数
// async function main(params, caller) { ... }
// 函数只会被定义但不会被执行,且形参会遮蔽全局变量函数返回值
函数的最后一个表达式的值将作为返回值。你也可以使用 return 语句显式返回。返回值会被 JSON 序列化,大小不超过 1MB。
// 示例:简单的函数
const greeting = params.name || 'World'
return { message: `Hello, ${greeting}!` }内置 API
云函数内置 API 已整理到独立页面,便于按对象快速查方法、参数、返回值和示例:
- 云函数内置 API 速查 —
$data、$permission、$account、$storage、$crypto、$certificates、$appleIap、$invoke、fetch - 跨应用访问 — 使用
withBasic(clientId, clientSecret)访问目标应用资源
| 内置对象 | 用途 | 常用入口 |
|---|---|---|
$data | 数据合集桥接 | get / set / list / update / createOnce / incAtomic |
$permission | 权限组桥接 | checkPermission / assignRole |
$account | 账号只读查询 | getUser / findUser / getAvatar |
$storage | 文件存储桥接 | getUploadUrl / getDownloadUrl / list |
$crypto | 加密、摘要和验签 | encrypt / decrypt / hash / hmac / timingSafeEqual |
$certificates | 固定引用应用级发布的 JWS/X.509 策略 | policy / hasPolicy |
$appleIap | 使用发布策略完成 App Store Server API 交易查询与通知验签 | createApiToken / getTransactionInfo / verifyNotification |
$invoke | 函数互调 | $invoke() / withBasic() |
fetch | 公网 HTTP 请求 | fetch(url, options) |
默认情况下,
$data、$permission、$storage和$invoke访问当前云函数所属应用的资源;跨应用访问请使用withBasic并把目标应用密钥放在环境变量中。
API 接口
调用云函数
支持通过路径嵌套调用文件夹中的函数:
POST /cf/api/{functionName}
POST /cf/api/{folder}/{functionName}
GET /cf/api/{functionName}
GET /cf/api/{folder}/{functionName}
Content-Type: application/json只有 invokeAccess = http 的函数可以通过 HTTP/API 调用。是否允许 GET、POST 或两者皆可由函数的 invokeMethod 配置决定。post 为默认值。
路径参数:
| 参数 | 类型 | 说明 |
|---|---|---|
functionName | string | 函数名称 |
folder | string | 可选,文件夹路径 |
必需请求头:
| 请求头 | 说明 |
|---|---|
Authorization | 认证信息(Basic / Bearer) |
X-Timestamp | Unix 时间戳(秒) |
X-Nonce | 16~64 字符的随机字符串 |
POST 请求体:
{
"params": {
"key": "value"
}
}
params为可选字段,默认为空对象{}。
GET 查询参数:
?params=<JSON 对象>:例如?params=%7B%22platform%22%3A%22win64%22%7D- 未提供
params时,普通查询参数会直接作为params对象传入,例如?platform=win64会得到{ "platform": "win64" }
成功响应:
{
"result": {
"message": "Hello, World!"
},
"logs": ["[LOG] Processing request..."],
"durationMs": 12
}超时响应(HTTP 400):
{
"error": "timeout",
"error_description": "Function execution timed out after 5000ms",
"logs": [],
"durationMs": 5000
}执行错误响应(HTTP 400):
{
"error": "execution_error",
"error_description": "ReferenceError: foo is not defined",
"logs": ["[LOG] Starting..."],
"durationMs": 3
}匿名调用云函数(公开端点)
当云函数的 requireAuth 设置为 0 时,可通过公开端点无需身份验证直接调用。该端点适用于不需要识别调用者身份的公共场景(如版本检查、公告获取、静态计算等)。
POST /cf/api/public/{clientId}/{functionName}
POST /cf/api/public/{clientId}/{folder}/{functionName}
GET /cf/api/public/{clientId}/{functionName}
GET /cf/api/public/{clientId}/{folder}/{functionName}
Content-Type: application/json公开 GET 端点可直接在浏览器地址栏打开,适合版本检查、公告读取等无敏感信息的只读函数。
路径参数:
| 参数 | 类型 | 说明 |
|---|---|---|
clientId | string | 应用的 client_id(可公开,不涉及 client_secret) |
functionName | string | 函数名称 |
folder | string | 可选,文件夹路径 |
⚠️ 注意:
- 公开端点无需
Authorization、X-Timestamp或X-Nonce请求头。- 云函数内
caller.mode为"anonymous",caller.uid为undefined。- 仅
requireAuth=0的函数可通过此端点调用;若函数需要认证(requireAuth=1,默认值),此端点会返回403 auth_required。- 仅
invokeAccess=http的函数可通过此端点调用;invokeAccess=cloud_function会返回403 invoke_access_denied。- 仍会检查
invokeMethod;例如配置为get的函数不能通过POST调用。- 请勿在匿名函数内执行涉及用户身份的敏感操作(写入用户数据、扣费、发放奖励等)。
API 端点响应结构
云函数可以在函数设置中选择 outputMode,影响带认证的 /cf/api/... 与匿名 /cf/api/public/... 响应结构。Raw HTTP 端点 /cf/http/public/... 使用自定义 HTTP 响应规则,不受 outputMode 影响。
假设函数返回:
return { state: 'Hello', version: 'Dev 0.45' }| outputMode | 响应 |
|---|---|
default | {"result":{"state":"Hello","version":"Dev 0.45"},"logs":[],"durationMs":28} |
direct | {"state":"Hello","version":"Dev 0.45"} |
mixed | {"logs":[],"durationMs":28,"state":"Hello","version":"Dev 0.45"} |
mixed 仅在函数返回值是对象且不是数组时合并;如果函数返回值中的 key 与 logs 或 durationMs 冲突,以函数返回值为准。若返回字符串、数字、数组等非对象值,则退回默认包装结构。
请求参数与响应:GET 使用查询参数,POST 使用请求体;响应结构由 outputMode 决定。
示例(浏览器直接访问):
https://api.starecho.net/cf/api/public/abc123/version_check示例(UE5 / 客户端 POST 直连):
curl -X POST https://api.starecho.net/cf/api/public/abc123/version_check \
-H "Content-Type: application/json" \
-d '{"params":{"platform":"win64"}}'该端点专为不方便携带应用密钥或用户 token 的场景设计,例如游戏客户端的更新检查、未登录用户查询公告等。
Raw HTTP 公开云函数(第三方 Webhook)
Raw HTTP 入口用于承载第三方 Webhook、支付回调、平台回调等“不按 { params } 格式提交”的请求。它会把请求方法、请求头、query、原始 body、解析后的 body、IP 和路径传入云函数,并允许云函数返回自定义 HTTP 状态码、响应头和响应体。
该入口只对显式设置 requestMode=raw 的函数开放。管理面板、管理 API 和 VS Code 插件/MCP 均可创建、查询和更新该字段,并会返回可直接配置给第三方的 rawHttpUrl。 未开启 Raw 模式的函数访问此路径会得到 403 raw_http_disabled。
POST /cf/http/public/{clientId}/{functionName}
POST /cf/http/public/{clientId}/{folder}/{functionName}
GET /cf/http/public/{clientId}/{functionName}
GET /cf/http/public/{clientId}/{folder}/{functionName}Raw HTTP 入口仍然要求函数满足以下条件:
| 条件 | 说明 |
|---|---|
requireAuth=0 | 第三方平台通常不会携带 StarEcho Bearer token |
invokeAccess=http | cloud_function 私有函数不能被外部 HTTP 直接调用 |
requestMode=raw | 显式开启 Raw HTTP 输入协议;默认 wrapped 不开放此入口 |
invokeMethod 匹配 | get / post / both 仍会生效 |
| 应用已开通 Cloud Function 服务 | 与普通云函数一致 |
Raw HTTP 云函数中可以读取 request:
// request 只在 /cf/http/public/... 入口中有完整内容
const method = request.method
const headers = request.headers || {}
const query = request.query || {}
const rawBody = request.rawBody || ''
const rawBytes = request.rawBodyBase64 || ''
const body = request.body
const ip = request.ip
const path = request.path
const url = request.url字段说明:
| 字段 | 说明 |
|---|---|
request.method | GET 或 POST |
request.headers | 请求头对象;key 统一为小写以便大小写不敏感读取,值保持原始内容 |
request.query | query 参数对象 |
request.rawBody | 解析前保存的原始 body 的 UTF-8 字符串视图,用于文本/JSON 验签 |
request.rawBodyBase64 | 原始 body 字节的 Base64;二进制协议应使用该字段避免 UTF-8 转换损失 |
request.rawBodyLength | 原始 body 的准确字节数 |
request.body | JSON 请求会解析为对象;非 JSON 请求为字符串或 null |
request.ip | 调用来源 IP,优先读取 Cloudflare / 反代头 |
request.path | 不含 query 的当前请求路径 |
request.url | 包含 query 的实际请求 URL |
rawBody/rawBodyBase64 在 JSON 解析前捕获,平台不会通过 JSON.stringify(request.body) 重建。单次 Raw 请求正文上限为 1 MiB(高于 256 KiB 兼容基线);超限由 Fastify 路由直接返回真实 HTTP 413。
Raw HTTP 入口支持自定义响应:
return {
statusCode: 204,
headers: {},
body: '',
}如果返回值不是包含 statusCode 的对象,平台会按 200 直接返回该值。普通 /cf/api/... 和 /cf/api/public/... 的包装响应行为不变。Raw 响应不受 outputMode=default/direct/mixed 影响;运行时异常返回真实 500,超时返回真实 504。
Webhook 验签示例:
const authorization = String(request.headers?.authorization || '')
const signature = authorization.match(/^Signature\s+([a-f0-9]+)$/i)?.[1] || ''
const expected = $crypto.hash('sha1', request.rawBody + env.WEBHOOK_SECRET, 'hex')
if (!$crypto.timingSafeEqual(signature, expected)) {
return { statusCode: 400, body: { error: 'invalid_signature' } }
}
return { statusCode: 204, body: '' }管理面板的云函数模板中提供“通用 JWS/X.509 策略验签”“Apple IAP 服务端验证”和 “Xsolla Raw Webhook”。它们会自动选择 Raw、匿名 HTTP、POST-only 的兼容配置。Apple 模板 使用三个固定的发布策略,分别 await 验证 Notifications V2 外层、交易和续订 JWS;任一 策略返回可重试依赖错误时响应 503,永久失败响应 400,验证成功后才按 notificationUUID 幂等写入。Xsolla 模板按 Authorization: Signature <hex> 对精确正文与 Secret 的 SHA-1 结果做常量时间比较,并返回真实 204/400。
幂等发货示例:
const event = request.body || {}
const eventId = event.notification_id || event.id
const uid = event.uid
const amount = Number(event.amount || 0)
if (!eventId || !uid || amount <= 0) {
return { statusCode: 400, body: { error: 'invalid_payload' } }
}
await $data.transaction(async tx => {
const created = await tx.createOnce('payment_events', String(eventId), {
type: event.type,
uid,
amount,
createdAt: Date.now(),
})
if (!created.created) return
await tx.incAtomic('wallets', uid, { balance: amount }, {
ownerUid: uid,
createIfMissing: true,
})
})
return { statusCode: 204, body: '' }部署提示:如果 Cloudflare 安全规则只放行了
/cf/api/,还需要额外放行/cf/http/。当前 nginx 使用location ^~ /cf/反代时不需要为该路径单独新增规则。 数据库管理员应从源码仓库单独执行scripts/database/20260725-add-cloud-function-secrets.sql。数据库迁移不会进入dist/或生产部署压缩包。生产环境还应设置SITE_API_URL=https://api.starecho.net,否则管理 API 生成的rawHttpUrl会使用本地默认地址。
错误响应
所有错误响应遵循统一格式:
{
"error": "error_code",
"error_description": "Human-readable error message"
}常见错误码:
| 错误码 | HTTP 状态码 | 说明 |
|---|---|---|
unauthorized | 401 | 缺少 Authorization 请求头 |
invalid_client | 401 | 无效的 Basic 凭据 |
invalid_token | 401 | 无效的 Bearer token |
replay_detected | 403 | 请求重放或时间戳过期 |
service_not_enabled | 403 | 应用未开通云函数服务 |
invoke_access_denied | 403 | 函数设置为仅允许云函数内 $invoke 调用 |
raw_http_disabled | 403 | 函数没有显式设置 requestMode=raw |
auth_required | 403 | 该函数不允许匿名调用(requireAuth=1) |
method_not_allowed | 405 | 当前 HTTP 方法不在函数 invokeMethod 允许范围内 |
disabled | 403 | 函数已被禁用 |
not_found | 404 | 函数不存在 |
payload_too_large | 413 | Raw HTTP 请求正文超过 1 MiB |
timeout | 400 / 504 | 传统入口为 400;Raw HTTP 入口为真实 504 |
execution_error | 400 / 500 | 传统入口为 400;Raw HTTP 入口为真实 500 |
完整示例
使用 Basic 认证调用
const res = await fetch(`${API_BASE}/cf/api/calculate_score`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
'X-Timestamp': Math.floor(Date.now() / 1000).toString(),
'X-Nonce': crypto.randomUUID().replace(/-/g, ''),
},
body: JSON.stringify({
params: { level: 5, combo: 120, accuracy: 0.95 }
}),
})
const data = await res.json()
console.log(data.result.score)使用环境变量
在管理面板中设置普通配置变量(如 URL、环境名称和功能开关),在函数中通过 env 访问。 密钥应放在应用级或函数级 Secret 中。
普通配置输入内容必须是 JSONC 对象,不是 .env 文件的 KEY=value 格式。 支持 //、/* */ 注释和尾随逗号,注释会在保存和备份恢复后保留。对象的键会成为函数内 env 的属性:
部署该能力前需执行独立迁移 database_migrations/20260731-expand-cloud-function-config-vars.sql,将保存加密 JSONC 源文本的 config_vars 扩展为 MEDIUMTEXT。迁移不会修改现有配置内容。
{
// 生产发布前关闭测试入口
"ENABLE_TEST_PAYMENT": false,
"WEBHOOK_URL": "https://example.com/hook",
}函数代码中通过 env.KEY 读取:
const message = `Player ${caller.uid} completed level ${params.level}`
console.log(`Sending notification: ${message}`)
return {
notified: true,
webhook: env.WEBHOOK_URL,
message
}基于调用者身份的逻辑
if (caller.mode === 'user') {
return { greeting: `Welcome, player ${caller.uid}!` }
} else {
return { greeting: 'Server-to-server call' }
}推荐模式:用户认证 + 权限检查 + 数据操作
以下是分发给用户的游戏客户端中推荐的云函数调用模式。客户端使用 Bearer 模式(用户 access_token)调用云函数——无需将 client_secret 嵌入客户端。
开发者无需自行验证
access_token。平台会在云函数执行之前自动完成 JWT 签名和过期时间的验证。如果 token 无效或已过期,请求会直接被拦截并返回401 invalid_token,云函数代码不会执行。开发者只需关注业务层的权限检查。
客户端调用:
// 客户端代码(游戏/前端)—— 使用用户的 access_token
const res = await fetch(`${API_BASE}/cf/api/submit_score`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`, // 用户登录后获取的 token
'X-Timestamp': Math.floor(Date.now() / 1000).toString(),
'X-Nonce': crypto.randomUUID().replace(/-/g, ''),
},
body: JSON.stringify({
params: { level: 5, score: 9800 }
}),
})云函数代码:
// caller 对象由平台自动注入,token 已验证通过
// caller.mode = "user"
// caller.uid = "用户 uid"
// caller.clientId = "应用 ID"
// ✅ 只需检查业务权限,无需验证 token
const { allowed } = await $permission.checkPermission(caller.uid, 'leaderboard.submit')
if (!allowed) {
return { error: 'no_permission', message: '无提交排行榜权限' }
}
// 业务逻辑:存储分数
await $data.set('leaderboard', caller.uid, {
level: params.level,
score: params.score,
submittedAt: new Date().toISOString(),
}, caller.uid)
return { success: true, message: '分数已提交' }云函数 + $data + $permission 综合示例
// 示例:带权限检查的物品发放系统
const { adminUid, targetUid, itemId, quantity } = params
// 1. 检查管理员权限
const check = await $permission.checkPermission(adminUid, 'inventory.grant')
if (!check.hasPermission) {
return { error: '权限不足', required: 'inventory.grant' }
}
// 2. 获取目标用户背包
const bag = await $data.get('inventory', targetUid).catch(() => null)
const items = bag?.document?.data?.items || {}
// 3. 添加物品
items[itemId] = (items[itemId] || 0) + quantity
// 4. 保存
await $data.set('inventory', targetUid, { items, lastModified: new Date().toISOString() }, targetUid)
console.log(`Admin ${adminUid} granted ${quantity}x ${itemId} to ${targetUid}`)
return { success: true, itemId, quantity, newTotal: items[itemId] }