Skip to content

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 个字母数字字符,每次请求不同
http
X-Timestamp: 1719000000
X-Nonce: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

核心概念 ​

函数数量额度与扩容 ​

应用默认可创建 50 个云函数。管理页和以下管理接口会返回 functionQuota,其中包含 used、limit、remaining、maximumLimit 与最近一次申请状态:

http
GET /cf/manage/{clientId}/overview
GET /cf/manage/{clientId}/functions

应用所有者可提交扩容申请;提高额度需管理员审核,批准值可低于申请值,但必须高于当前额度:

http
POST /oauth/apps/{clientId}/cloud-function-limit/request
Authorization: Bearer <owner_access_token>
Content-Type: application/json

{
  "requestedLimit": 100,
  "reason": "正式环境将按业务域拆分下载、支付和通知函数"
}

创建函数和额度审批使用同一应用级互斥锁,避免并发创建越过生效额度。扩容申请复用平台 服务申请与管理员审核流程,不要求开发者直接联系 R2 或修改服务器配置。

云函数(Cloud Function) ​

云函数是一段在沙盒环境中执行的 JavaScript 代码。每个云函数有以下属性:

属性类型说明
namestring函数名称,在应用内唯一,只允许字母、数字、下划线
descriptionstring函数描述
folderstring | null文件夹路径,用于组织函数
timeoutnumber超时时间(ms),范围 5,000 ~ 30,000;支付等网络密集函数可配置 30 秒
enablednumber是否启用(1 = 启用)
requireAuthnumber是否需要身份验证(1 = 需要,默认;0 = 匿名公开)
invokeAccessstring调用入口:http(默认,允许 HTTP/API 和 $invoke)或 cloud_function(仅允许 $invoke)
invokeMethodstringHTTP 调用方式:post(默认)、get、both
outputModestringAPI 端点响应结构:default(默认)、direct、mixed
requestModestring输入协议:wrapped(默认 { params })或显式 raw(第三方 Webhook)
rawHttpUrlstring | null管理 API 生成的 Raw 公开 URL;仅 requestMode=raw 时返回
configVarsobject可读回的普通配置,适合 URL、开关、Bundle ID 等非敏感内容;通过 env 访问
configVarsSourcestring普通配置的 JSONC 源文本,保留 //、/* */ 注释和尾随逗号
envVarsobject兼容入口,现为只写函数级 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 和时间戳:

http
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 的备份与恢复 ​

选择“云函数”导出时,请求只需要选择服务:

http
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) ​

定时规则用于周期性触发云函数。规则由管理接口维护:

http
GET    /cf/manage/{clientId}/cron
POST   /cf/manage/{clientId}/cron
PUT    /cf/manage/{clientId}/cron/{ruleId}
DELETE /cf/manage/{clientId}/cron/{ruleId}

创建或更新规则时常用字段:

字段类型说明
namestring可选,定时规则显示名称
functionUidstring主目标云函数 UID
cronExprstring5 段 cron 表达式:分 时 日 月 周
scheduleTypestringcron、workday、holiday、festival
scheduleConfigstring可视化调度配置 JSON 字符串,用于多时间点、节日等场景
functionTargetsstring可选,多目标函数 UID JSON 数组;为空时只执行 functionUid
timeZonestringIANA 时区,例如 Asia/Shanghai、UTC
paramsobject定时触发时合并传入云函数的 JSON 参数
maxExecutionsnumber最大执行次数,0 或空表示不限制
enablednumber更新时可设置,1 启用、0 禁用

定时触发时,云函数以应用身份运行,params 会先合并规则中的自定义参数,再覆盖写入系统字段:

js
{
  ...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:

变量类型说明
paramsobject调用方传入的参数(只读)
envobject合并后的普通配置和 Secret(只读,保留既有 env.KEY 行为)
callerobject调用者信息(只读)
caller.modestring"user"、"app" 或 "anonymous"
caller.uidstring | undefined用户 uid(仅 user 模式存在)
requestobjectRaw HTTP 入口专用的原始请求上下文;普通 /cf/api/... 调用为空对象
consoleobject日志输出(log, warn, error, info)
$dataobject数据合集内置 API,支持原子操作、排序、条件过滤
$permissionobject权限组内置 API
$accountobject账号内置 API,用于查询用户最小信息和头像时效链接
$storageobject文件存储内置 API,支持上传、下载、删除、列表
$cryptoobject加密内置 API,支持 AES-256-GCM、hash、HMAC、ES256 JWS
$certificatesobjectJWS/X.509 发布策略,只允许固定引用当前应用的已发布版本
$secretsobject只写 Secret 引用,管理端无法读回 Secret 值
$appleIapobjectApple IAP 托管 API,支持 API Token 与服务端交易查询
$invokefunction函数互调,可调用同应用或通过 withBasic 跨应用调用云函数
fetchfunctionHTTP 请求,仅限公网地址
btoa / atobfunctionBase64 编解码

还包括标准 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。

javascript
// ✅ 正确写法:直接编写代码
const name = params.name || 'World'
return { message: `Hello, ${name}!` }

// ❌ 错误写法:不要定义 main 函数
// async function main(params, caller) { ... }
// 函数只会被定义但不会被执行,且形参会遮蔽全局变量

函数返回值 ​

函数的最后一个表达式的值将作为返回值。你也可以使用 return 语句显式返回。返回值会被 JSON 序列化,大小不超过 1MB。

javascript
// 示例:简单的函数
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 接口 ​

调用云函数 ​

支持通过路径嵌套调用文件夹中的函数:

http
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 为默认值。

路径参数:

参数类型说明
functionNamestring函数名称
folderstring可选,文件夹路径

必需请求头:

请求头说明
Authorization认证信息(Basic / Bearer)
X-TimestampUnix 时间戳(秒)
X-Nonce16~64 字符的随机字符串

POST 请求体:

json
{
  "params": {
    "key": "value"
  }
}

params 为可选字段,默认为空对象 {}。

GET 查询参数:

  • ?params=<JSON 对象>:例如 ?params=%7B%22platform%22%3A%22win64%22%7D
  • 未提供 params 时,普通查询参数会直接作为 params 对象传入,例如 ?platform=win64 会得到 { "platform": "win64" }

成功响应:

json
{
  "result": {
    "message": "Hello, World!"
  },
  "logs": ["[LOG] Processing request..."],
  "durationMs": 12
}

超时响应(HTTP 400):

json
{
  "error": "timeout",
  "error_description": "Function execution timed out after 5000ms",
  "logs": [],
  "durationMs": 5000
}

执行错误响应(HTTP 400):

json
{
  "error": "execution_error",
  "error_description": "ReferenceError: foo is not defined",
  "logs": ["[LOG] Starting..."],
  "durationMs": 3
}

匿名调用云函数(公开端点) ​

当云函数的 requireAuth 设置为 0 时,可通过公开端点无需身份验证直接调用。该端点适用于不需要识别调用者身份的公共场景(如版本检查、公告获取、静态计算等)。

http
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 端点可直接在浏览器地址栏打开,适合版本检查、公告读取等无敏感信息的只读函数。

路径参数:

参数类型说明
clientIdstring应用的 client_id(可公开,不涉及 client_secret)
functionNamestring函数名称
folderstring可选,文件夹路径

⚠️ 注意:

  • 公开端点无需 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 影响。

假设函数返回:

javascript
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 决定。

示例(浏览器直接访问):

text
https://api.starecho.net/cf/api/public/abc123/version_check

示例(UE5 / 客户端 POST 直连):

bash
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。

http
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=httpcloud_function 私有函数不能被外部 HTTP 直接调用
requestMode=raw显式开启 Raw HTTP 输入协议;默认 wrapped 不开放此入口
invokeMethod 匹配get / post / both 仍会生效
应用已开通 Cloud Function 服务与普通云函数一致

Raw HTTP 云函数中可以读取 request:

javascript
// 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.methodGET 或 POST
request.headers请求头对象;key 统一为小写以便大小写不敏感读取,值保持原始内容
request.queryquery 参数对象
request.rawBody解析前保存的原始 body 的 UTF-8 字符串视图,用于文本/JSON 验签
request.rawBodyBase64原始 body 字节的 Base64;二进制协议应使用该字段避免 UTF-8 转换损失
request.rawBodyLength原始 body 的准确字节数
request.bodyJSON 请求会解析为对象;非 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 入口支持自定义响应:

javascript
return {
  statusCode: 204,
  headers: {},
  body: '',
}

如果返回值不是包含 statusCode 的对象,平台会按 200 直接返回该值。普通 /cf/api/... 和 /cf/api/public/... 的包装响应行为不变。Raw 响应不受 outputMode=default/direct/mixed 影响;运行时异常返回真实 500,超时返回真实 504。

Webhook 验签示例:

javascript
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。

幂等发货示例:

javascript
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 会使用本地默认地址。

错误响应 ​

所有错误响应遵循统一格式:

json
{
  "error": "error_code",
  "error_description": "Human-readable error message"
}

常见错误码:

错误码HTTP 状态码说明
unauthorized401缺少 Authorization 请求头
invalid_client401无效的 Basic 凭据
invalid_token401无效的 Bearer token
replay_detected403请求重放或时间戳过期
service_not_enabled403应用未开通云函数服务
invoke_access_denied403函数设置为仅允许云函数内 $invoke 调用
raw_http_disabled403函数没有显式设置 requestMode=raw
auth_required403该函数不允许匿名调用(requireAuth=1)
method_not_allowed405当前 HTTP 方法不在函数 invokeMethod 允许范围内
disabled403函数已被禁用
not_found404函数不存在
payload_too_large413Raw HTTP 请求正文超过 1 MiB
timeout400 / 504传统入口为 400;Raw HTTP 入口为真实 504
execution_error400 / 500传统入口为 400;Raw HTTP 入口为真实 500

完整示例 ​

使用 Basic 认证调用 ​

javascript
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。迁移不会修改现有配置内容。

jsonc
{
  // 生产发布前关闭测试入口
  "ENABLE_TEST_PAYMENT": false,
  "WEBHOOK_URL": "https://example.com/hook",
}

函数代码中通过 env.KEY 读取:

javascript
const message = `Player ${caller.uid} completed level ${params.level}`
console.log(`Sending notification: ${message}`)
return {
  notified: true,
  webhook: env.WEBHOOK_URL,
  message
}

基于调用者身份的逻辑 ​

javascript
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,云函数代码不会执行。开发者只需关注业务层的权限检查。

客户端调用:

javascript
// 客户端代码(游戏/前端)—— 使用用户的 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 }
  }),
})

云函数代码:

javascript
// 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 综合示例 ​

javascript
// 示例:带权限检查的物品发放系统

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] }

© 2026 StarEcho