cloud-obj.md 22.1 KB
Newer Older
雪洛's avatar
雪洛 已提交
1 2 3 4
## 云对象

> 新增于 HBuilderX 3.4.0

5
## 背景和优势
雪洛's avatar
雪洛 已提交
6

7
20年前,restful接口开发开始流行,服务器编写接口,客户端调用接口,传输json。
雪洛's avatar
雪洛 已提交
8

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
现在,替代restful的新模式来了。

云对象,服务器编写API,客户端调用API,不再开发传输json的接口。思路更清晰、代码更精简。

比如服务端编写一个云对象todo,该对象有add、get、remove、update等方法。客户端的js则可以直接import这个todo云对象,直接调用add等方法。

服务器示例代码如下:

HBuilderX中在uniCloud/cloudfunctions目录新建云函数,选择类型为云对象,起名为todo。打开云对象入口index.obj.js,添加一个add方法。

```js
// 云对象名:todo
module.exports = {
	add(title, content) {
		title = title.trim()
		content = content.trim()
		if(!title || !content) {
			return {
				errCode: 'INVALID_TODO',
				errMsg: 'TODO标题或内容不可为空'
			}
		}
		// ...其他逻辑
		return {
			errCode: 0,
			errMsg: '创建成功'
		}
	}
}
```

然后在客户端的js中,import这个todo对象,调用它的add方法

```js
const todo = uniCloud.importObject('todo') //第一步导入云对象
async function addTodo () {
	try {
		const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
		uni.showToast({
			title: '创建成功'
		})
	} catch (e) {
		// 符合uniCloud响应体规范 https://uniapp.dcloud.net.cn/uniCloud/cf-functions?id=resformat,自动抛出此错误 
		uni.showModal({
			title: '创建失败',
			content: e.errMsg,
			showCancel: false
		})
	}
}
```

可以看到云对象的代码非常清晰,代码行数也只有33行。

而同样的逻辑,使用传统的接口方式则需要更多代码,见下:
雪洛's avatar
雪洛 已提交
64 65 66

```js
// 传统方式调用云函数-云函数代码
雪洛's avatar
雪洛 已提交
67
// 云函数名:todo
雪洛's avatar
雪洛 已提交
68 69 70 71
// 云函数入口index.js内容如下
'use strict';
exports.main = async (event, context) => {
	const {
雪洛's avatar
雪洛 已提交
72
		method,
雪洛's avatar
雪洛 已提交
73 74
		params
	} = event
雪洛's avatar
雪洛 已提交
75
	switch(method) {
雪洛's avatar
雪洛 已提交
76 77 78 79
		case 'add': {
			let {
				title,
				content
雪洛's avatar
雪洛 已提交
80
			} = params
雪洛's avatar
雪洛 已提交
81 82 83
			title = title.trim()
			content = content.trim()
			if(!title || !content) {
雪洛's avatar
雪洛 已提交
84
				return {
雪洛's avatar
雪洛 已提交
85 86
					errCode: 'INVALID_TODO',
					errMsg: 'TODO标题或内容不可为空'
雪洛's avatar
雪洛 已提交
87 88
				}
			}
雪洛's avatar
雪洛 已提交
89
			// ...省略其他逻辑
雪洛's avatar
雪洛 已提交
90 91
			return {
				errCode: 0,
雪洛's avatar
雪洛 已提交
92
				errMsg: '创建成功'
雪洛's avatar
雪洛 已提交
93 94 95 96
			}
		}
	}
	return {
雪洛's avatar
雪洛 已提交
97 98
		errCode: 'METHOD_NOT_FOUND',
		errMsg: `Method[${method}] not found`
雪洛's avatar
雪洛 已提交
99 100 101 102
	}
};

// 传统方式调用云函数-客户端代码
雪洛's avatar
雪洛 已提交
103
async function addToDo () {
雪洛's avatar
雪洛 已提交
104 105
	try {
		const res = uniCloud.callFunction({
雪洛's avatar
雪洛 已提交
106
			name: 'todo', 
雪洛's avatar
雪洛 已提交
107
			data: {
雪洛's avatar
雪洛 已提交
108
				method: 'add',
雪洛's avatar
雪洛 已提交
109
				params: {
雪洛's avatar
雪洛 已提交
110 111
					title: 'title demo',
					content: 'content demo'
雪洛's avatar
雪洛 已提交
112 113 114 115 116 117 118 119 120
				}
			}
		})
		const {
			errCode,
			errMsg
		} = res.result
		if(errCode) {
			uni.showModal({
雪洛's avatar
雪洛 已提交
121
				title: '创建失败',
雪洛's avatar
雪洛 已提交
122 123 124 125 126 127
				content: errMsg,
				showCancel: false
			})
			return
		}
		uni.showToast({
雪洛's avatar
雪洛 已提交
128
			title: '创建成功'
雪洛's avatar
雪洛 已提交
129 130 131
		})
	} catch (e) {
		uni.showModal({
雪洛's avatar
雪洛 已提交
132
			title: '创建失败',
雪洛's avatar
雪洛 已提交
133 134 135 136 137 138 139
			content: e.message,
			showCancel: false
		})
	}
}
```

140
以上传统开发需要68行代码,对比云对象的33行代码,不但工作量大,而且逻辑也不如云对象清晰。
雪洛's avatar
雪洛 已提交
141

142
_注:以上例子仅用于方便初学者理解。实际开发中对于简单的数据库操作,使用[clientDB](/uniCloud/clientdb)在前端直接操作数据库是更简单、代码更少的方案,都不需要写云端代码。
雪洛's avatar
雪洛 已提交
143

144 145 146 147 148
总结下云对象带来的好处:
1. 更清晰的逻辑
2. 更精简的代码
3. 更少的协作成本(以及矛盾~)
4. 客户端调用时在ide里有完善的代码提示,方法参数均可提示。(传输json可没法在ide里提示)
149 150
5. 默认支持[uniCloud响应体规范](uniCloud/cf-functions.md?id=resformat),方便错误拦截和统一处理

151
注:目前云对象还不支持URL化和定时触发,未来会补充
雪洛's avatar
雪洛 已提交
152

雪洛's avatar
雪洛 已提交
153
## 快速上手
雪洛's avatar
雪洛 已提交
154

雪洛's avatar
雪洛 已提交
155
### 创建云对象
雪洛's avatar
雪洛 已提交
156

157 158 159 160 161
云对象,其实是对云函数的封装。和创建云函数一样,在`uniCloud/cloudfunctions`目录右键新建云函数,选择云对象类型,输入云对象名称创建云对象,此处以云对象todo为例,创建的云对象包含一个`index.obj.js`

![创建云对象](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/1c2bff0e-3c93-4417-bc21-90a842c779af.jpg)

一个空的云对象内容如下
雪洛's avatar
雪洛 已提交
162 163

```js
雪洛's avatar
雪洛 已提交
164
// cloudfunctions/todo/index.obj.js
雪洛's avatar
雪洛 已提交
165
module.exports = {
雪洛's avatar
雪洛 已提交
166
	
雪洛's avatar
雪洛 已提交
167 168 169
}
```

雪洛's avatar
雪洛 已提交
170
默认云对象模板是不包含任何方法的,我们为此对象添加一个add方法作为示例。
雪洛's avatar
雪洛 已提交
171

雪洛's avatar
雪洛 已提交
172 173 174 175 176 177 178 179 180 181 182 183
```js
// cloudfunctions/todo/index.obj.js
module.exports = {
	add: function(title = '', content = '') {
		title = title.trim()
		content = content.trim()
		if(!title || !content) {
			return {
				errCode: 'INVALID_TODO',
				errMsg: 'TODO标题或内容不可为空'
			}
		}
184
		// ...其他逻辑,如操作todo数据表添加数据
雪洛's avatar
雪洛 已提交
185 186 187 188 189 190 191
		return {
			errCode: 0,
			errMsg: '创建成功'
		}
	}
}
```
雪洛's avatar
雪洛 已提交
192

雪洛's avatar
雪洛 已提交
193 194 195 196 197
至此云对象todo已经有了一个可以访问的方法了。接下来看如何使用客户端调用此云对象内的方法

### 客户端调用

客户端通过`uniCloud.importObject`方法获取云对象的实例,并可以通过此实例调用云对象内的方法。用法如下
雪洛's avatar
雪洛 已提交
198 199

```js
雪洛's avatar
雪洛 已提交
200 201
const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
雪洛's avatar
雪洛 已提交
202 203
```

雪洛's avatar
雪洛 已提交
204 205 206 207 208 209
通过代码块`cco`可以快捷的输入以下代码:

```js
const todo = uniCloud.importObject('todo')
```

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
实际业务中需要考虑错误捕获,调用方式有两种:

1. try catch
```js
const todo = uniCloud.importObject('todo')
try {
	const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
	console.log(res)
} catch (e) {
	console.log(e.errCode)
	console.log(e.errMsg)
}
```

2. then catch(promise写法)
```js
const todo = uniCloud.importObject('todo')
todo.add('title demo', 'content demo').then(res => {
	console.log(res)
}).catch(e => {
	console.log(e.errCode)
	console.log(e.errMsg)
})
```

雪洛's avatar
雪洛 已提交
235

雪洛's avatar
雪洛 已提交
236
## 云对象的API@api
雪洛's avatar
雪洛 已提交
237

238 239 240 241
云对象作为云函数的一种,可以调用所有node的API和uniCloud的API。

uniCloud有众多API,另见:[uniCloud的API清单](uniCloud/cf-functions.html#unicloud-api%E5%88%97%E8%A1%A8)

W
wanganxp 已提交
242 243 244
除上述API之外,云对象的this对象还有一批专用方法来获取当前请求的上下文信息。

与云函数入参时的`context`不同,云对象没有`context`。它通过this对象挂载的几个内置方法来获取上下文信息。请注意开发者避免在this上挂载同名方法。
雪洛's avatar
雪洛 已提交
245 246 247

### 获取客户端信息@get-client-info

雪洛's avatar
雪洛 已提交
248 249
> HBuilderX 3.4.9起此接口可获取所有客户端`getSystemInfo`返回的客户端信息,完整字段列表参考:[getSystemInfo](https://uniapp.dcloud.net.cn/api/system/info.html#getsysteminfo)

雪洛's avatar
雪洛 已提交
250 251 252 253 254
**接口形式**

`this.getClientInfo()`

**示例:**
雪洛's avatar
雪洛 已提交
255 256

```js
雪洛's avatar
雪洛 已提交
257 258 259 260 261
module.exports = {
	add: function() {
		const clientInfo = this.getClientInfo()
		// clientInfo = {
		// 	clientIP,
W
wanganxp 已提交
262
		// 	appId,
雪洛's avatar
雪洛 已提交
263
		// 	deviceId,
264
		// 	source,
雪洛's avatar
雪洛 已提交
265
		// 	//... 其他getSystemInfoSync返回值
雪洛's avatar
雪洛 已提交
266 267 268
		// }
	}
}
雪洛's avatar
雪洛 已提交
269 270
```

雪洛's avatar
雪洛 已提交
271
**返回值**
雪洛's avatar
雪洛 已提交
272

雪洛's avatar
雪洛 已提交
273
getClientInfo返回的信息,是在客户端的[uni.getSystemInfo](https://uniapp.dcloud.net.cn/api/system/info.html#getsysteminfo)的基础之上,增加了一些额外的信息。
雪洛's avatar
雪洛 已提交
274

雪洛's avatar
雪洛 已提交
275 276 277 278 279
除了`getSystemInfo`返回字段外,还包含以下信息

|属性名		|类型	|说明																											|
|--			|--		|--																												|
|clientIP	|string	|客户端ip																										|
280 281
|source		|string	|调用来源,返回值见下。新增于`HBuilderX 3.5.1`								|
|scene		|string	|场景值。客户端[uni.getLaunchOptionsSync](/api/plugins/getLaunchOptionsSync.html#getlaunchoptionssync)返回的scene参数,新增于`HBuilderX 3.5.1`	|
雪洛's avatar
雪洛 已提交
282

283 284 285 286 287 288
getClientInfo().source,返回云函数调用来源,它的值域为:

|取值		|说明								|
|--			|--									|
|client		|uni-app客户端导入云对象调用			|
|function	|由其他云函数或云对象调用		|
雪洛's avatar
雪洛 已提交
289

290 291 292 293 294 295
未来云对象支持URL化后,source 会增加 http、timing。

**注意事项**
- 客户端上报的信息在理论上存在被篡改可能,实际业务中应验证前端传来的数据的合法性
- 除了clientIP外,其他客户端信息只有使用uni-app客户端以云对象的方式调用才能获取
- 云对象与云函数内获取客户端platform稍有不同,云函数未拉齐vue2、vue3版本app平台的platform值,vue2为`app-plus`,vue3为`app`。云对象无论客户端是vue2还是vue3,在app平台获取的platform均为`app`。这一点在使用uni-id时需要特别注意,详情见:[uni-id文档 preferedAppPlatform](uniCloud/uni-id.md?id=prefered-app-platform)
雪洛's avatar
雪洛 已提交
296 297 298 299 300 301 302 303

### 获取云端信息@get-cloud-info

**接口形式**

`this.getCloudInfo()`

**示例**
雪洛's avatar
雪洛 已提交
304 305

```js
雪洛's avatar
雪洛 已提交
306 307 308 309 310
module.exports = {
	add: function(){
		const cloudInfo = this.getCloudInfo()
		// cloudInfo = {
		//     provider,
雪洛's avatar
雪洛 已提交
311
		//     spaceId,
雪洛's avatar
雪洛 已提交
312
		//     functionRuntimeVersion,
雪洛's avatar
雪洛 已提交
313 314
		//     functionName,
		//     functionType,
雪洛's avatar
雪洛 已提交
315 316 317 318 319 320 321
		// }
	}
}
```

**返回值**

雪洛's avatar
雪洛 已提交
322 323
|参数名			|类型	|必备	|说明																								|
|--				|--		|--		|--																									|
324
|provider		|string	|是		|服务空间供应商,阿里云为:`aliyun`,腾讯云为:`tencent`														|
雪洛's avatar
雪洛 已提交
325
|spaceId		|string	|是		|服务空间Id																							|
雪洛's avatar
雪洛 已提交
326
|functionRuntimeVersion		|string	|是		|服务端sdk版本,本地调试插件随HBuilderX更新,云端保持与最新HBuilderX一致(无论本地版本多少,云端只有一个最新版本的云函数sdk),新增于`HBuilderX 3.5.1`	|
雪洛's avatar
雪洛 已提交
327 328
|functionName	|string	|是		|云对象名称,新增于`HBuilderX 3.5.1`																|
|functionType	|string	|是		|云对象此值固定为`cloudobject`,新增于`HBuilderX 3.5.1`																|
雪洛's avatar
雪洛 已提交
329 330 331

### 获取客户端token@get-uni-id-token

W
wanganxp 已提交
332 333
云对象自动管理`uni-id`的token。开发者无需手动管理。如果不了解`uni-id`,请[参考](/uniCloud/uni-id-summary)

雪洛's avatar
雪洛 已提交
334 335 336 337 338 339 340 341 342 343
**接口形式**

`this.getUniIdToken()`

**示例**

```js
module.exports = {
	add: function(){
		const token = this.getUniIdToken()
W
wanganxp 已提交
344 345 346
		if(!token) {
			// 登录状态无效
		}
雪洛's avatar
雪洛 已提交
347 348
	}
}
雪洛's avatar
雪洛 已提交
349 350
```

W
wanganxp 已提交
351

雪洛's avatar
雪洛 已提交
352 353
### 获取当前调用的方法名@get-method-name

354 355
本方法主要用于在`_before`等拦截器方法里,判断客户端上传的信息进行处理,比如发现客户端调用的是a方法时,执行一段特殊逻辑。详见下文的[预处理](uniCloud/cloud-obj?id=before-and-after)

雪洛's avatar
雪洛 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
**接口形式**

`this.getMethodName()`

**示例**

```js
module.exports = {
	_before: function() { // _before的用法请看后续章节
		const methodName = this.getMethodName() // add
	}
}
```

### 获取当前参数列表@get-params

372 373
在云对象的普通方法里,参数可以直接获取。本方法主要用于在_`_before`等拦截器方法里,判断客户端上传的信息进行处理。详见下文的[预处理](uniCloud/cloud-obj?id=before-and-after)

雪洛's avatar
雪洛 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
**接口形式**

`this.getParams()`

**示例**

```js
module.exports = {
	_before: function() { // _before的用法请看后续章节
		const params = this.getParams() // ['title demo', 'content demo']
	}
}
```

## 预处理与后处理@before-and-after

### 预处理 _before@before

W
wanganxp 已提交
392
云对象内可以创建一个特殊的方法`_before`,用来在调用常规方法之前进行预处理,一般用于拦截器、统一的身份验证、参数校验等。
雪洛's avatar
雪洛 已提交
393

W
wanganxp 已提交
394
以下示例的逻辑是,当客户端调用todo云对象的add方法时,会先执行`_before`方法中的逻辑,判断为add方法时校验了客户端token,校验失败则直接报错返回客户端,校验通过继续执行add方法。
雪洛's avatar
雪洛 已提交
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415

```js
// todo/index.obj.js
module.exports = {
	_before: function(){
		const methodName = this.getMethodName()
		if(methodName === 'add' && !this.getUniIdToken()) {
			throw new Error('token不存在')
		}
	},
	add: function(title = '', content = '') {
		return {
			errCode: 0,
			errMsg: '创建成功'
		}
	}
}
```

### 后处理 _after@after

416
与预处理`_before`对应的是后处理`_after`。云对象内可以创建一个特殊的方法`_after`用来再加工处理本次调用方法的返回结果或者抛出的错误
雪洛's avatar
雪洛 已提交
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444

请看以下示例:

```js
// todo/index.obj.js
module.exports = {
	_before: function(){
		this.startTime = Date.now() // 在before内记录开始时间并在this上挂载,以供后续流程使用
	},
	add: function(title = '', content = '') {
		if(title === 'abc') {
			throw new Error('abc不是一个合法的todo标题')
		}
		return {
			errCode: 0,
			errMsg: '创建成功'
		}
	},
	_after(error, result) {
		if(error) {
			throw error // 如果方法抛出错误,也直接抛出不处理
		}
		result.timeCost = Date.now() - this.startTime
		return result
	}
}
```

W
wanganxp 已提交
445 446
注意:所有`_`开头的方法都是私有方法,客户端不可访问。也就是客户端调用云对象时不能调用_开头的方法。

雪洛's avatar
雪洛 已提交
447
## 云对象的返回值@return-value
雪洛's avatar
雪洛 已提交
448

W
wanganxp 已提交
449 450 451 452 453 454 455
云对象返回给客户端的数据,包括正常数据和错误对象。

理论上,开发者可以使用任意方式返回正确状态下的数据格式,返回字符串、json对象都可以。

但在错误处理时,推荐使用[uniCloud响应体规范](uniCloud/cf-functions.md?id=resformat),以方便客户端统一拦截错误。

在云对象内部报错时,比如方法名错误等非开发者代码返回的错误,会自动使用[uniCloud响应体规范](uniCloud/cf-functions.md?id=resformat)抛出错误对象。
雪洛's avatar
雪洛 已提交
456

W
wanganxp 已提交
457
开发者代码在主动报错时,比如参数校验错误,由于不能直接写入错误对象(e),则需要按照[uniCloud响应体规范](uniCloud/cf-functions.md?id=resformat)在返回的json对象中加入`errCode``errMsg`
雪洛's avatar
雪洛 已提交
458

459
uni-app框架在拿到云对象的响应结果后,会识别其中是否包含`errCode``errMsg`,然后自动创建报错对象(e),策略如下:
W
wanganxp 已提交
460 461 462 463 464

- 如果是正常的结果(errCode为假值[0, false, null, undefined, ...]或者结果内不含errCode),不抛出错误对象(e)
- 如果是报错的结果(errCode为真值)将结果内的errCode和errMsg组合为错误对象(e)抛出
- 如果是其他云函数未捕获的错误,直接将错误码和错误信息组合成错误对象(e)抛出

465
也就是说,开发者的前端代码调用云对象时,需要try catch或者then catch。不报错时,在`try`里或`then()``res`里直接返回结果,报错时在`catch (e) {}`里拿到错误对象e。
W
wanganxp 已提交
466

W
wanganxp 已提交
467 468
不管是系统错误(如网络问题、云函数超时问题),还是开发者业务上的反馈错误,都如此,都是在 `catch` 中捕获错误。

W
wanganxp 已提交
469
客户端抛出的错误对象(e)有以下属性
雪洛's avatar
雪洛 已提交
470 471 472 473 474

|属性名		|类型				|是否必备	|说明													|
|--			|--					|--			|--														|
|errCode	|string|number	|否			|错误码													|
|errMsg		|string				|否			|错误信息												|
W
wanganxp 已提交
475 476 477
|requestId	|string				|否			|当前请求的requestId。本地调试无此值,需在服务空间运行		|
|detail		|Object				|否			|完整的错误响应(仅在响应符合uniCloud响应体规范时才有)	|

雪洛's avatar
雪洛 已提交
478

479

雪洛's avatar
雪洛 已提交
480 481 482
详见以下示例:

```js
W
wanganxp 已提交
483
// 云对象代码 todo/index.obj.js
雪洛's avatar
雪洛 已提交
484
module.exports = {
雪洛's avatar
雪洛 已提交
485 486 487 488
	add: async function(title = '', content = '') { 
		title = title.trim()
		content = content.trim()
		if(!title || !content) {
雪洛's avatar
雪洛 已提交
489
			return {
雪洛's avatar
雪洛 已提交
490 491
				errCode: 'INVALID_TODO',
				errMsg: 'TODO标题或内容不可为空'
雪洛's avatar
雪洛 已提交
492 493
			}
		}
雪洛's avatar
雪洛 已提交
494
		// ...其他逻辑
雪洛's avatar
雪洛 已提交
495 496
		return {
			errCode: 0,
雪洛's avatar
雪洛 已提交
497
			errMsg: '创建成功'
雪洛's avatar
雪洛 已提交
498 499 500
		}
	}
}
W
wanganxp 已提交
501
```
雪洛's avatar
雪洛 已提交
502

W
wanganxp 已提交
503
```js
雪洛's avatar
雪洛 已提交
504
// 客户端代码
雪洛's avatar
雪洛 已提交
505
const todo = uniCloud.importObject('todo')
W
wanganxp 已提交
506 507

// 不传title、content,云函数返回错误的响应
雪洛's avatar
雪洛 已提交
508
try {
雪洛's avatar
雪洛 已提交
509
	await todo.add()
雪洛's avatar
雪洛 已提交
510
} catch (e) {
雪洛's avatar
雪洛 已提交
511 512 513
	// e.errCode === 'INVALID_TODO'
	// e.errMsg === 'TODO标题或内容不可为空'
	// e.detail === {errCode: 'INVALID_TODO',errMsg: 'TODO标题或内容不可为空'}
雪洛's avatar
雪洛 已提交
514 515 516
	// e.requestId === 'xxxx'
}

W
wanganxp 已提交
517
// 传入正确的title、content,云函数返回原始响应
雪洛's avatar
雪洛 已提交
518
try {
雪洛's avatar
雪洛 已提交
519 520
	const res = await todo.add('title demo', 'content demo')
	// res = {errCode: 0,errMsg: '创建成功'}
雪洛's avatar
雪洛 已提交
521 522 523
} catch (e) {}
```

524 525 526
**注意**
- js错误对象不是json,直接console.log(e),只能得到被toString()后的errMsg。而不是一个展开的json结构。

雪洛's avatar
雪洛 已提交
527

528
## 云对象的多种调用方式
雪洛's avatar
雪洛 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564

### 客户端调用@call-by-client

客户端通过`uniCloud.importObject`方法获取云对象的实例。用法如下

```js
const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
```

### 云函数或云对象内调用@call-by-cloud

云函数或云对象内也可以调用同一服务空间内的云对象,用法和客户端调用云对象一致

```js
const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
```

### 跨服务空间调用云对象@call-by-cloud-cross-space

云端或者客户端均有uniCloud.init方法可以获取其他服务空间的uniCloud实例,使用此实例的importObject可以调用其他服务空间的云对象,参考:[](uniCloud/concepts/space.md?id=multi-space)

客户端无论腾讯阿里均支持。云端`uniCloud.init`方法仅腾讯云支持,且仅能获取同账号下的腾讯云服务空间的uniCloud实例。

**示例代码**

```js
const mycloud = uniCloud.init({
	provider: 'tencent',
	spaceId: 'xxx'
})
const todo = mycloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
```

565 566
**注意**
- 上述示例代码,在实际开发中均应该使用 try catch 或 then catch 处理错误捕获
W
wanganxp 已提交
567 568 569 570 571 572 573 574

### 云对象的接收参数的体积上限
- 阿里云接收参数大小不可超过1MB
- 腾讯云接收参数大小不可超过6MB

由于传输层还有上下文环境信息,所以开发者给云对象发送参数时需注意控制参数体积


575
## 自动显示交互界面@auto-ui
雪洛's avatar
雪洛 已提交
576

577 578
> 新增于 HBuilderX 3.4.6,本次调整属于非兼容更新。

579
背景:每次写客户端联网的代码时,开发者都免不了重复写一堆代码:先调用loading等待框,联网结束后再关闭loading,如果服务器异常则弹出提示。
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604

从HBuilderX 3.4.6起,调用云对象的方法时,默认会自动显示交互/提示界面。

1. 在请求联网开始时显示loading等待框,
2. 结束后隐藏loading
3. 如果请求报错,显示弹窗(也可配置为显示Toast)

如果默认显示的UI不符合你的需求,你可以通过配置自定义一些交互内容,也可以直接关闭自动显示的交互界面。

- 如需关闭自动显示的UI,请在客户端导入云对象时传入参数`customUI: true`

例:

```js
uniCloud.importObject('todo', {
	customUI: true // 取消自动展示的交互提示界面
})
```

- 如需自定义默认显示的UI,配置如下:

```js
uniCloud.importObject('todo', {
	customUI: false, // 是否取消自动展示的交互界面。默认为false,配置为true时取消自动展示的交互提示界面,以下配置均不再生效
	loadingOptions: { // loading相关配置
雪洛's avatar
雪洛 已提交
605
		title: '加载中...', // 显示的loading内的提示文字。默认值为:加载中...
606 607 608 609 610 611 612 613 614
		mask: true // 是否使用透明遮罩,配置为true时不可点击页面其他内容。默认值为:true
	},
	errorOptions: { // 错误界面相关配置
		type: 'modal', // 错误信息展示方式,可取值:modal(弹框,默认)、toast(toast消息框)。默认值为:modal
		retry: false // 是否展示重试按钮,仅在type为modal时生效。用户点击重试按钮时将重新请求调用的方法,默认为false
	}
})
```

615 616 617
**注意**
1. 配置仅对当前`importObject`返回的云对象实例生效
2. 本功能仅对客户端调用云对象生效。在云函数或云对象中调用云对象不生效
雪洛's avatar
雪洛 已提交
618 619


雪洛's avatar
雪洛 已提交
620 621
## 本地运行@run-local

622 623 624
`HBuilderX 3.4.8`之前,云对象无法直接本地运行。可以通过其他云函数调用本地云对象(在调用云对象的云函数右键本地运行),或者客户端调用本地云对象的方式来实现云对象的本地运行。

`HBuilderX 3.4.8`起,云对象可以本地运行。打开云对象下的js文件,按Ctrl+r或点击运行菜单运行云对象。
雪洛's avatar
雪洛 已提交
625

626
运行云对象之前需要先选择执行云对象的哪个方法,以及传递什么参数。
雪洛's avatar
雪洛 已提交
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

以下述云对象为例:

```js
module.exports = {
	login(username, password) {
		// ...
		return {
			errCode: 0
		}
	}
}

```

调用login方法,传递username及password参数,的运行参数配置如下:

![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/db974aec-7975-45b7-bb64-24afd8a59213.jpg)
645

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
## jsdoc+语法提示

HBuilderX中所有js方法都支持jsdoc+的语法提示系统。

在方法的开头通过`/**`输入特定格式的注释,在调用这个云对象的方法时就可以看到参数提示。

```js
/**
 * method1方法描述
 * @param {string} param1 参数1描述
 * @returns {object} 返回值描述
 */
method1(param1) {
	if (!param1) {
		return {
			errCode: 'PARAM_IS_NULL',
			errMsg: '参数不能为空'
		}
	}
	return {
		param1 //请根据实际需要返回值
	}
}
```

调用该方法时可以看到代码提示:
![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/a94aa7c2-daa6-4bcb-a74c-d0e5c5c58b12.jpg)


675 676 677 678
## 注意事项

- 云对象和云函数都在cloudfunctions目录下,但是不同于云函数,云对象的入口为`index.obj.js`,而云函数则是`index.js`**为正确区分两者uniCloud做出了限制,云函数内不可存在index.obj.js,云对象内也不可存在index.js。**
- 所有`_`开头的方法都是私有方法,客户端不可访问
W
wanganxp 已提交
679 680 681 682 683
- 云对象也可以引用公共模块或者npm上的包,引用方式和云函数一致。

## 复杂示例

DCloud官方开发了 `uni-id-co`,这是一个较为复杂的云对象,用于搭配 [uni-id-pages](https://ext.dcloud.net.cn/plugin?id=8577) 实现云端一体的用户注册登录等功能。该代码开源,可以参考。
684

685 686 687 688 689 690 691 692
## 推荐最佳实践

uniCloud的服务器和客户端交互,有云函数、云对象、clientDB三种方式。

从云对象发布后,不再推荐使用传统云函数了。

如果是以数据库操作为主,则推荐使用clientDB,开发效率是最高的。

W
wanganxp 已提交
693 694 695
如果服务器端不操作数据库外,或者还有复杂的、不宜公开在前端的逻辑,此时推荐使用云对象。

但云对象仅适用于与uni-app前端交互使用。如果不与uni-app前端交互,比如使用云函数URL化与其他系统通信、或者使用定时云函数,此时不适用云对象,还是需要使用云函数。