简体中文
普通云函数
callFunction方式云函数,也称之为普通云函数。
uni-app的前端代码,不再执行uni.request
联网,而是通过uniCloud.callFunction
调用云函数。
callFunction方式避免了服务器提供域名,不暴露固定ip,减少被攻击的风险。
uniCloud.callFunction
可以在uni-app前端执行,也可以在uniCloud云函数中执行。也就是前端和云端都可以调用另一个云函数。
callFunction
方法的参数和返回值如下:
uniCloud.callFunction
需要一个json对象作为参数,其中包含2个字段
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
name | String | 是 | 云函数名称 |
data | Object | 否 | 客户端需要传递的参数 |
timeout | Number | 否 | 超时时间,单位ms,默认60000, 新增于HBuilderX 4.25 |
返回json
字段 | 类型 | 说明 |
---|---|---|
result | Object | 云函数中代码return的返回结果 |
requestId | String | 云函数请求序列号,用于错误排查,可以在uniCloud web控制台的云函数日志中查到 |
header | Object | 服务器header信息 |
errCode | Number或String | 服务器错误码 |
success | bool | 执行是否成功 |
注意:
header
,需要在云端运行云函数才会返回返回格式,下文有详细解读 详见
前端示例代码
假使云服务空间有一个云函数名为“hellocf”,那么前端可以通过如下方式调用这个云函数
// promise方式
uniCloud.callFunction({
name: 'hellocf',
data: { a: 1 }
})
.then(res => {});
// callback方式
uniCloud.callFunction({
name: 'hellocf',
data: { a: 1 },
success(){},
fail(){},
complete(){}
});
客户端callFunction调用云函数时,云函数通过入参接收客户端数据,通过头信息上下文获取客户端信息,经过业务逻辑处理后给客户端返回结果。
假使客户端代码调用云函数hellocf
,并传递了{a:1,b:2}
的数据,
// 客户端调用云函数并传递参数
uniCloud.callFunction({
name: 'hellocf',
data: {a:1,b:2}
})
.then(res => {});
那么云函数侧的代码如下,将传入的两个参数求和并返回客户端:
// hellocf云函数index.js入口文件代码
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
let c = event.a + event.b
return {
sum: c
} // 通过return返回结果给客户端
}
云函数的传入参数有两个,一个是event
对象,一个是context
对象。
event
指的是触发云函数的事件。当客户端调用云函数时,event
就是客户端调用云函数时传入的参数。context
对象包含了本次请求的上下文,包括客户端的ip、ua、appId等信息,以及云函数的环境情况、调用来源source等信息。event对象,可以理解为客户端上行参数中的json对象。在使用uni-id
且登录成功后,会自动多添加了一个uniIdToken
属性。
可以通过 event.uniIdToken
获取 uni-id 的 token,如下:
'use strict';
exports.main = async (event, context) => {
let token = event.uniIdToken // 客户端uni-id token
}
所以开发者需注意,自己上行的参数对象不要包含uniIdToken属性,避免同名冲突。
入参的体积限制
云函数上行的参数内容不能传太大。
context
对象包含了本次请求的上下文,包括客户端的ip、ua、appId等信息,以及云函数的环境情况、调用来源source等信息。context对象的属性清单如下:
属性名称 | 类型 | 说明 |
---|---|---|
SPACEINFO | object | 服务空间信息 |
|- spaceId | string | 服务空间id |
|- provider | string | 服务空间供应商:alipay|aliyun|tencent |
|- useOldSpaceId | boolean | 当前获取的服务空间id是否为迁移前的服务空间id,新增于HBuilderX 3.6.13 |
SOURCE | string | 云函数调用来源 详见 |
FUNCTION_NAME | string | 获取云函数名称 |
FUNCTION_TYPE | string | 获取云函数类型,对于云函数来说,这里一定会返回cloudfunction ,新增于HBuilderX 3.5.1。 |
CLIENTIP | string | 客户端IP。如果调用来源是其他服务器,会返回调用方的ip |
CLIENTUA | string | 客户端userAgent。注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云函数,但是云函数会从http请求头里面获取ua而不是clientInfo里面的ua |
uniIdToken | string | 客户端uni-id token字符串,新增于HBuilderX 3.5.1。 |
requestId | string | 当前请求id,新增于HBuilderX 3.5.5。 |
RUNTIME_ENV | string | 运行环境,取值为local (本地运行)或cloud (云端运行),新增于HBuilderX 4.25。 |
除了上述属性,如果是uni-app客户端通过callfunction访问云函数,那么context还会追加一批客户端信息。
uni.getSystemInfo
的所有属性。比如appId、osName,均以驼峰方式命名。这些属性较多,且可能跟随前端API更新而变化,具体详见 uni.getSystemInfo为了保持向下兼容,新版并没有去掉老版那些大写属性的客户端信息,但文档标注为以废弃。对于新版HBuilderX用户而言,请使用 uni.getSystemInfo
返回的驼峰属性。
HBuilderX 3.4.9起,context 的属性还可以打印出channel
和scene
,即App的渠道包标记和小程序场景值。但这个功能属于未完成功能,开发者暂不使用这2个属性,后续会升级完善。目前如开发者需要这2个属性,请自行在客户端使用uni.getLaunchOptionsSync上传。
示例:
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
//...
//context中可获取客户端调用的上下文
let clientIP = context.CLIENTIP // 客户端ip信息
let spaceInfo = context.SPACEINFO // 当前环境信息 {spaceId:'xxx',provider:'tencent'}
let source = context.SOURCE // 云函数调用来源
// 以下属性只有使用uni-app以callFunction方式调用才能获取,即context.SOURCE=="client",调用方不是uni-app客户端则没有相应数据
let appid = context.appId // manifest.json中配置的appid
let deviceId = context.deviceId // 客户端标识,新增于HBuilderX 3.1.0,同uni-app客户端getSystemInfo接口获取的deviceId
//... //其它业务代码
}
context.SOURCE,返回云函数调用来源,它的值域为:
取值 | 解释 |
---|---|
client | 客户端callFunction方式调用 |
http | 云函数url化方式调用 |
timing | 定时触发器调用 |
function | 由其他云函数callFunction调用 |
server | 由uniCloud管理端调用,HBuilderX里上传并运行 |
'use strict';
exports.main = async (event, context) => {
let source = context.SOURCE // 当前云函数被何种方式调用
// client 客户端callFunction方式调用
// http 云函数url化方式调用
// timing 定时触发器调用
// server 由管理端调用,HBuilderX里上传并运行
// function 由其他云函数callFunction调用
}
注意事项
context.PLATFORM
的取值,有 app
和 app-plus
两种情况。
app
app-plus
,uni-app 3.4.9起,该值修改为了app
除了CLIENTIP外,其他客户端信息只有使用uni-app客户端以callFunction方式调用才能获取。如果云函数url化后被uni-app通过request调用,也没有客户端信息。
在云函数URL化的场景无法获取客户端平台信息,可以在调用依赖客户端平台的接口接口之前(推荐在云函数入口)通过修改context.PLATFORM手动传入客户端平台信息供其他插件(如:uni-id)使用
例:
exports.main = async (event, context) => {
context.PLATFORM = 'app'
}
普通云函数返回给客户端的是json格式数据。返回结果包裹在result下。
前端发起callFunction到云端接收参数并响应,然后反馈前端,前端接收,完整流程代码如下:
// 客户端发起调用云函数hellocf,并传入data数据
uniCloud.callFunction({
name: 'hellocf',
data: {a:1,b:2}
}).then((res) => {
console.log(res.result) // 结果是 {sum: 3}
}).catch((err) => {
console.error(err)
})
// 云函数hellocf的代码,接收到客户端传递的data,并对其中a和b相加返回给客户端
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
console.log('event : ', event)
//返回数据给客户端
return {sum : event.a + event.b}
};
那么客户端得到的res结构如下
{
"errCode": 0,
"errMsg": "",
"header": {
"access-control-expose-headers": "Date,x-fc-request-id,x-fc-error-type,x-fc-code-checksum,x-fc-invocation-duration,x-fc-max-memory-usage,x-fc-log-result,x-fc-invocation-code-version"
"content-disposition": "attachment"
"content-length": "38"
"content-type": "application/json"
"date": "Sat, 25 Jun 2022 19:28:34 GMT"
"x-fc-code-checksum": "92066386860027743"
"x-fc-instance-id": "c-62b761c4-5a85e238b3ce404c817d"
"x-fc-invocation-duration": "23"
"x-fc-invocation-service-version": "LATEST"
"x-fc-max-memory-usage": "66.61"
"x-fc-request-id": "80854b93-b0c7-43ab-ab16-9ee9f77ff41e"
"x-serverless-request-id": "ac1403831656185314624173902"
"x-serverless-runtime-version": "1.2.2"
}
"requestId": "ac1403831656185314624173902"
"result": {sum: 3}
"success": true
}
其中result
是开发者云函数代码返回的数据,其余是云平台返回的。
注意:HBuilderX本地运行云函数时,如果没有系统错误,则只返回result
,其他需要在云端运行云函数才会返回。
uniCloud响应体规范
为了方便统一拦截错误,推荐开发者使用 uniCloud响应体规范
业务报错时,在 result 里返回 errCode 和 errMsg。如下:
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
console.log('event : ', event)
if (!event.a) {
return {errCode : 1,errMsg : "参数a不能为空"}
}
if (!event.b) {
return {errCode : 2,errMsg : "参数b不能为空"}
}
const c = event.a + event.b
if (isNaN(c)) {
return {errCode : 3,errMsg : "参数a和b无法求和"}
}
//返回数据给客户端
return {sum:c,errCode : 1,errMsg : "0"}
};