云对象,其实是对云函数的封装。
创建云对象
在uniCloud/cloudfunctions目录右键新建云函数,选择云对象类型,输入云对象名称创建云对象,此处以云对象testco为例,创建的云对象包含一个index.obj.js。
// testco/index.obj.js
module.exports = {
_before: function(){
this.startTime = Date.now() // 在before内记录开始时间并在this上挂载,以供后续流程使用
},
add: async function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
},
_after(error, result) {
if(error) {
throw error // 如果方法抛出错误,也直接抛出不处理
}
result.timeCost = Date.now() - this.startTime
return result
},
_timing: function () {
console.log('triggered by timing')
}
}
客户端调用
客户端通过uniCloud.importObject
方法获取云对象的实例,并可以通过此实例调用云对象内的方法。用法如下
const testco = uniCloud.importObject('testco') //第一步导入云对象
try {
const res = await testco.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步
} catch (e) {
console.log(e)
}
云函数或云对象内调用
云函数或云对象内也可以调用同一服务空间内的云对象,用法和客户端调用云对象一致
const todo = uniCloud.importObject('testco')
const res = await todo.add('title demo', 'content demo')
云对象多个方法共享逻辑
一个云对象导出的不同方法之间不能互相调用。比如下面示例中 tryAddTodo 方法内部无法调用 addTodo 方法。
只能将多个方法共享的逻辑放到云对象导出的对象外部来供云对象的方法调用。例如下面抽离公共函数 pureAddTodo
// todo.obj.js
// 方法前的async是根据自己的业务来的,不是必须async
async function pureAddTodo(title, content) {
// ...add todo 逻辑
}
module.exports = {
async tryAddTodo() {
try {
return addTodo(title, content) // 一定会失败。只能调用 pureAddTodo 这样的非导出方法。
} catch (e) {
return {
errCode: 'add-todo-failed'
}
}
},
async addTodo(title, content) {
return pureAddTodo(title, content)
}
}
云对象API
云对象作为云函数的一种,可以调用所有node的API和uniCloud的API。
除上述API之外,云对象的this对象还有一批专用方法来获取当前请求的上下文信息。
与云函数入参时的context不同,云对象没有context。它通过this对象挂载的几个内置方法来获取上下文信息。请注意开发者避免在this上挂载同名方法。
- 获取客户端信息this.getClientInfo()
- 获取云端信息this.getCloudInfo()
- 获取客户端token this.getUniIdToken()
- 获取当前调用的方法名this.getMethodName()
方法主要用于在_before等拦截器方法里,判断客户端上传的信息进行处理,比如发现客户端调用的是a方法时,执行一段特殊逻辑。
- 获取当前参数列表 this.getParams()
在云对象的普通方法里,参数可以直接获取。本方法主要用于在__before等拦截器方法里,判断客户端上传的信息进行处理。
- 获取当前请求id this.getUniCloudRequestId()
- 获取url化时的http信息 this.getHttpInfo()
仅可在云对象url化时使用
httpInfo为集成请求格式的对象,结构如下
{
path: 'HTTP请求路径,如 /hello',
httpMethod: 'HTTP请求方法,如 GET',
headers: {HTTP请求头},
queryStringParameters: {HTTP请求的Query,键值对形式},
body: 'HTTP请求体',
isBase64Encoded: 'true or false,表示body是否为Base64编码'
}
内置特殊方法
目前有3个内置特殊方法:_before、_after、_timing
预处理 _before:一般用于拦截器、统一的身份验证、参数校验等。
后处理 _after:用来再加工处理本次调用方法的返回结果或者抛出的错误
定时运行 _timing:定时任务
云对象url化
url化:当需要外部系统访问云对象时,可以把云对象封装成一个HTTP的URL。
示例
使用GET请求https://${云对象Url化域名}/${触发路径}/${云对象方法名}?a=1&b=2
,云对象接收到的event为
{
path: '/${云对象方法名}',
httpMethod: 'GET',
headers: {HTTP请求头},
queryStringParameters: {a: "1", b: "2"},
isBase64Encoded: false
}
使用POST请求https://${云对象Url化域名}/${触发路径}/${云对象方法名}
,云对象接收到的event.body为请求发送的数据,uni.request默认content-type为application/json
// 以uni.request为例
uni.request({
method: 'POST',
url: 'https://${云对象Url化域名}/${触发路径}/${云对象方法名}',
data: {
a: 1,
b: 2
},
success(res) {
console.log(res);
}
})
云对象入参,请使用this.getHttpInfo获取
// 云对象的httpInfo
{
path: '/${云对象方法名}',
httpMethod: 'POST',
headers: {
...
"content-type": 'application/json'
},
isBase64Encoded: false,
body: '{"a":1,"b":2}', // 注意此处可能是base64,需要根据isBase64Encoded判断
}
云对象返回值
常见的string、object、number 返回格式:application/json
返回集成响应
比如返回二进制文件,图片音频之类的
{
mpserverlessComposedResponse: true, // 使用阿里云返回集成响应是需要此字段为true
isBase64Encoded: true,
statusCode: 200,
headers: {
'content-type': 'image/png'
},
body: 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAY...'
}
云对象中获取cookie
'use strict';
//引入cookie
const cookie = require('cookie')
module.exports = {
addTodo: function () {
const httpInfo = this.getHttpInfo()
const cookieData = cookie.parse(httpInfo.headers.cookie || '')
//设置cookie到客户端
const cookieOptions = {
//具体参数请查阅 https://www.npmjs.com/package/cookie
maxAge: 60 * 60 * 24 * 7,//一周
path:"/"
}
const setCookieData = cookie.serialize('app', 'appName', cookieOptions)
return {
statusCode: 200,
headers: {
'content-type': '返回数据类型',
'set-cookie': setCookieData // 在headers内返回set-cookie用于设置客户端cookie
},
body: '返回数据'
}
}
};
注意事项:阿里云目前请求与响应有如下限制,大小不能超过1M
接收到的post请求的请求体可能是被转成base64的,如果是这样需要进行一次转化。 以接收text/xml格式的post请求为例
比如:
// 云对象
module.exports = {
addTodo: function() {
let httpInfo = this.getHttpInfo()
let body = httpInfo.body
if(httpInfo.isBase64Encoded){
body = Buffer.from(body, 'base64').toString('utf8') // 将base64格式的xml内容转为xml字符串
}
}
}