跳到主要内容

在微信小程序中调用 CloudBase 云函数

一句话定义:用 wx.cloud.callFunction 直连云函数,云函数侧用 wx-server-sdk 自动拿到 OPENID/APPID/UNIONID,业务里不需要自建身份系统、不需要 HTTPS 域名、不需要 token 校验。

预计耗时:25 分钟 | 难度:入门

适用场景

这条路径走的是「微信·云开发」体系下的小程序前端调用云函数,跟 add-database-wechat-miniprogram 用的 @cloudbase/js-sdk 自定义登录是两条不同的链路,不要混着用。

  • 适用:已经在小程序里启用了云开发(wx.cloud.init 能跑),想从前端调一个能拿到 OPENID 的服务端逻辑
  • 适用:业务要拿 OPENID 才能跑(发模板/订阅消息、查老用户绑定关系、生成带身份的二维码)
  • 适用:不想自建 HTTPS 服务、不想在小程序里维护 token 续签逻辑
  • 不适用:想从 H5 / Web 端调同一个云函数(那一套要走 connect-openai-api-cloud-function 里的 HTTP 触发器)
  • 不适用:已经从微信·云开发迁到独立 CloudBase 环境,见 migrate-wxcloud-to-cloudbase

环境要求

依赖版本
小程序基础库2.2.3(wx.cloud 起步版本)
wx-server-sdk3.0.1
@cloudbase/cli(可选)1.27.0 起,用 tcb 命令行部署
微信开发者工具1.06.x

另外需要:

  • 一个已经开通的 CloudBase 环境,环境 ID 形如 your-env-id-1234567
  • 小程序 AppID 已在 CloudBase 控制台「环境配置 → 安全配置 → 小程序关联」里绑定到这个环境

第一步:控制台关联小程序 AppID 到 CloudBase 环境

CloudBase 控制台 → 选环境 → 环境配置 → 安全配置 → 小程序关联,把小程序的 AppID 填进去。

这一步是 wx.cloud.init({ env }) 鉴权的源头:小程序基础库会拿当前 AppID 去问云端「这个 AppID 能不能用这个 env」,关联记录不存在时直接报「非法的 env」,所有云函数调用、云数据库读写、云存储上传全部会失败。

后面写代码之前先把这一步完成,不然第三步 console 里只会看到一个语义不清的 errMsg。

第二步:写云函数(wx-server-sdk + getWXContext)

新建一个云函数目录(微信开发者工具里项目根的 cloudfunctions/ 下右键「新建 Node.js 云函数」,起名 add),里面有 index.jspackage.json 两个文件。

// cloudfunctions/add/index.js
const cloud = require('wx-server-sdk');

cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });

exports.main = async (event, context) => {
const wxContext = cloud.getWXContext();
return {
sum: event.x + event.y,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
};
};
// cloudfunctions/add/package.json
{
"name": "add",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"wx-server-sdk": "3.0.1"
}
}

三个细节:

  • cloud.DYNAMIC_CURRENT_ENV 让云函数运行时自动用「当前所在环境」,跨环境部署不需要改代码,这是从 latest 版本起的标准写法。
  • cloud.getWXContext() 返回的 OPENID/APPID/UNIONID 是从基础库到云函数全链路透传过来的,不是请求里带的字段,业务代码改不了也伪造不了,可以直接当身份用。
  • 没登录到任何账号的访客调用(比如分享出来的页面没授权)OPENID 仍然有值(基于会话的临时 openid),但 UNIONID 可能是空字符串,业务里要做空值兜底。

event 是小程序端 data 字段的原样透传,JSON 可序列化的都行。return 出去的对象会作为前端 res.result 拿到,不要返回 Date 实例(序列化会丢时区,改成 ISO 字符串再返)。

如果云函数里要操作数据库 / 存储 / 调其他云函数,wx-server-sdk 都已经把客户端封装好了,身份直接复用 getWXContext() 拿到的 OPENID,不需要再签 token:

// 在云函数里读数据库
const db = cloud.database();
const user = await db.collection('users').where({ _openid: wxContext.OPENID }).get();

// 在云函数里调另一个云函数
const res = await cloud.callFunction({ name: 'sendMessage', data: { ... } });

这是 BaaS 风格的核心价值:身份从客户端到云函数到数据库是一条直链,业务代码里看不到 token,也不需要管续签。

第三步:小程序端 wx.cloud.init + wx.cloud.callFunction

wx.cloud.callFunction 同时支持 Promise 和 callback,选哪个看场景:

  • Promise / async-await:页面逻辑串行多步操作时用,异常走 try / catch,可读性最好,90% 的场景选这个
  • callback(success / fail):基础库较低、跟其他 wx.* API 共用 callback 风格的工具函数(比如老项目的 wx.request 封装)时用,不需要再链一层 Promise.resolve

app.js 全局只初始化一次:

// app.js
App({
onLaunch() {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力');
return;
}
wx.cloud.init({
env: 'your-env-id-1234567',
traceUser: true,
});
},
});

traceUser: true 会在 CloudBase 控制台「用户管理」里记录一次本次会话的 openid + 最近活跃时间,方便后续在控制台直接看每天 DAU。不开也不影响功能。

页面里调用,只要走 Promise 形式就行:

// pages/index/index.js
Page({
async onTapAdd() {
try {
const res = await wx.cloud.callFunction({
name: 'add',
data: { x: 1, y: 2 },
});
console.log('result:', res.result);
// { sum: 3, openid: 'oABC...', appid: 'wxXXX...', unionid: '' }
} catch (err) {
console.error('callFunction failed', err);
}
},
});

也支持 callback 写法,传 success / fail 回调,跟 Promise 形式二选一:

wx.cloud.callFunction({
name: 'add',
data: { x: 1, y: 2 },
success: (res) => console.log(res.result),
fail: (err) => console.error(err),
});

name 是云函数名(不是文件路径),data 直接进云函数的 event,大小限制 5 MB。返回值在 res.result 里,不在 res.data,这是跟 wx.request 最容易记混的地方。

业务里常见的两个场景:

  • 跨环境临时切换:有测试 / 生产两套 env 时,在某次 callFunction 里临时指定环境,不用动 wx.cloud.init 全局配置:

    await wx.cloud.callFunction({
    name: 'add',
    data: { x: 1, y: 2 },
    config: { env: 'test-env-id-1234567' },
    });
  • 超时控制:wx.cloud.callFunction 没有 timeout 参数,前端会一直等到云函数返回。如果云函数本身可能跑 20 秒以上(比如调外部 LLM),要么在云函数里收口超时然后早返,要么前端用 Promise.race 套一层超时,不要把 UI 卡死。

第四步:用 tcb 部署或开发者工具一键部署

两条路,选一条就够了。

A. 微信开发者工具(适合刚起步)

cloudfunctions/add/ 目录右键 → 上传并部署:云端安装依赖(不上传 node_modules) → 等 30 秒 → 看到「上传成功」就可以在小程序里调了。

B. CLI(tcb 命令,适合 CI / 自动化)

# 装 CLI
npm install -g @cloudbase/cli

# 部署单个事件触发函数(不带 --httpFn,因为是给小程序 callFunction 用)
tcb fn deploy add -e your-env-id-1234567

部署完后到控制台云开发 → 函数 → 函数列表」能看到 add,点进去能看到运行内存、超时时间和最近调用日志。

注意:--httpFn 是给 HTTP 触发器用的(走公网域名调用),小程序 callFunction 是「事件触发」,加了 --httpFn 反而会让小程序端调用拿不到这个函数。一个云函数可以同时挂事件触发和 HTTP 触发,但走 HTTP 触发器进来的请求里没有 wxContext.OPENID,只有事件触发的调用才会自动透传身份。

tcb fn deploy 默认会读 cloudfunctions/<name>/package.json 里的 dependencies,在云端直接 npm install,本地不需要先装好 node_modules。如果有私有 npm 源或者要锁版本,提前在目录下放 .npmrcpackage-lock.json 即可。

第五步:在云函数里打日志(可选但强烈建议)

云函数没有「本地 console」可以看,所有的 console.log / console.error 都打到云端日志里,排查必须靠这条:

exports.main = async (event, context) => {
console.log('[add] event =', event);
const wxContext = cloud.getWXContext();
console.log('[add] wxContext =', wxContext);
// ... 业务逻辑
};

查日志的两个入口:

  • 微信开发者工具:左侧「云开发」面板 → 云函数 → 日志,只能看最近 24 小时
  • CloudBase 控制台「云开发 → 函数 → 函数列表 → 选函数 → 日志查询」,能按时间区间 / 关键字 / RequestId 过滤,保留 7 天

调试期建议每个云函数入口都打一行 eventwxContext,出问题时第一手看到的就是「调用进来的参数和身份对不对」,比起前端报错看到的 errMsg 信息量大得多。生产环境再视情况降级成只打 error

运行验证

  1. 微信开发者工具编译运行,触发那个调 wx.cloud.callFunction 的按钮
  2. 开发者工具 Console 应该看到 result: { sum: 3, openid: 'o...', appid: 'wx...', unionid: '...' },sum 必须等于 3
  3. 控制台 → 云开发 → 函数 → add → 日志查询,选最近 5 分钟,能看到一条 INFO 级别的运行记录,里面 event{ x: 1, y: 2 }returnValue 跟前端拿到的一致
  4. 把云函数里 cloud.init 那行注释掉再部署一次,前端调用应该报「请先调用 init」,确认整条链路是真的走到云函数,没有被任何中间层缓存住

第 4 条做完记得把代码改回来。

如果第 3 步在控制台日志里看不到本次调用,而前端 console 拿到了 res.result,99% 是部署没真生效——开发者工具有时会把上次部署的 zip 缓存住。强制重新打包:删掉本地 cloudfunctions/add/node_modules,在目录上右键「清除缓存并重新部署」,再调一次。

常见错误

错误信息原因修复
errCode: -404011 cloud function execution error 或 console 提示「非法的 env」第一步控制台没把 AppID 关联到这个 env,或者填错环境 ID控制台「环境配置 → 安全配置 → 小程序关联」加上当前小程序 AppID,确认 wx.cloud.init({ env }) 里的 env 跟控制台环境 ID 一致(末尾的随机串别漏)
Cloud API isn't enabled, please call wx.cloud.init first页面里直接 wx.cloud.callFunction,但 app.js onLaunch 里没调 wx.cloud.init,或者基础库低于 2.2.3wx.cloud.init 放进 app.js onLaunch,project.config.json 里 cloudfunctionRoot 也要配上
errCode: -501005 FUNCTIONS_EXECUTE_FAIL function not exists函数名拼错,或者本地写完没点「上传并部署」检查 name 字段跟云端函数名是否完全一致(大小写敏感),控制台「函数列表」里有这条记录才算部署成功
wxContext.OPENIDundefined没用 wx-server-sdkcloud.init,或者 event 解构覆盖了 context云函数顶部一定要 cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }),getWXContext() 才有数据;别把参数名写成 (event, wxContext) 之类
部署后立刻调用,第一次响应慢到 3-5 秒函数实例冷启动这是预期行为,Node.js 12 / 16 运行时冷启动一次后实例会保留 5-10 分钟,高频场景见 optimize-cloud-function-wechat-miniprogram
errCode: -601001 RESOURCE_INSUFFICIENT当月免费额度用完,或者按量付费账户欠费控制台「用量资源用量」看本月额度,按量套餐欠费会在欠费后 24 小时停服
errMsg: cloud.callFunction:fail Error: errCode: -502005 DATABASE_PERMISSION_DENIED云函数里访问数据库,但集合权限是「仅创建者可读写」,而调用方 OPENID 不是文档创建者云函数的执行身份继承调用方 OPENID,不是 admin。要绕过权限读全表,在云函数里改用 cloud.database({ env: ... }) 显式拿管理员客户端,或者把集合权限改成「仅管理端可读写」

完整错误码定义见 error-code

前端拿到的 errCode 一般就是云端透传过来的,先用错误码定位是「调不进去」(-404 / -501)还是「调进去了但里面跑挂」(-502 / -601),再决定看前端日志还是云函数日志,这一步比直接 google 错误信息高效得多。

相关文档