Uniapp云函数云对象
在 uni-app 的 uniCloud(云开发)生态中,**云函数(Cloud Functions)和云对象(Cloud Objects)**是编写服务端逻辑的两大核心利器。
简单来说,云对象是云函数的升级版(或者说是一种高级封装) 。它们的核心目的都是让你在前端直接调用后端代码,但在编写规范和开发体验上有着明显的区别。
下面我们来逐一详解它们的概念、代码实现以及核心区别。
一、 什么是云函数(Cloud Function)?
云函数是传统的 Serverless 服务端代码。每一个云函数都是一个独立的 Node.js 模块,运行在云端的沙箱环境中。
1. 工作原理
前端通过 uniCloud.callFunction 方法调用云函数,并向其传递一个 event 对象。云函数接收到 event 后进行逻辑处理,再将结果返回给前端。
2. 代码示例
-
云函数端(Backend):
javascript// 云函数 index.js exports.main = async (event, context) => { // event 包含前端传过来的参数 const { name, age } = event; if (!name) { return { code: 400, msg: '姓名不能为空' }; } return { code: 200, msg: `你好 ${name},你今年 ${age} 岁了。` }; }; -
前端调用(Frontend):
javascriptuniCloud.callFunction({ name: 'my-function', // 云函数名称 data: { name: '张三', age: 18 } }).then(res => { console.log(res.result); // 打印返回结果 });
3. 优缺点
- 优点:结构简单,适合处理单一、独立的业务逻辑(如定时任务、微信支付回调)。
- 缺点 :当一个模块有多个接口(如商品增删改查)时,要么建很多个云函数(导致管理混乱),要么在一个云函数里通过
switch-case编写路由(代码臃肿)。
二、 什么是云对象(Cloud Object)?
云对象是 DCloud 推出的一种面向对象的云开发模式。它把服务端的代码封装成一个"对象",对象里的每一个方法就对应一个接口。
1. 工作原理
在前端,你不需要关心 URL 或参数怎么打包,直接像导入本地 JS 对象一样导入远端的"云对象",然后直接调用它的方法。
2. 代码示例
-
云对象端(Backend):
javascript// 云对象 index.obj.js module.exports = { // 每一个方法就是一个接口 async sayHello(name, age) { if (!name) { return { code: 400, msg: '姓名不能为空' }; } return { code: 200, msg: `你好 ${name},你今年 ${age} 岁了。` }; }, async getGoodsList() { // 另一个接口逻辑... return { code: 200, data: [] }; } }; -
前端调用(Frontend):
javascript// 1. 导入云对象 const todoObject = uniCloud.importObject('my-object'); // 2. 直接像调用本地方法一样调用,参数直接传递 try { const res = await todoObject.sayHello('张三', 18); console.log(res); } catch(e) { console.error(e); }
3. 优缺点
- 优点:代码结构清晰,天然适合做内聚的业务模块(如用户模块、购物车模块);前端调用极其自然,HBuilderX 还能提供完美的方法名提示(代码补全)。
- 缺点:对于纯触发器(如定时任务、底层拦截器)或者特定第三方回调,依然需要传统的云函数结构。
三、 云函数 VS 云对象:核心区别
虽然云对象底层最终也会被编译/运行在云函数容器中(两者性能和计费完全一致),但在开发层面有以下本质区别:
| 对比维度 | 云函数 (Cloud Function) | 云对象 (Cloud Object) |
|---|---|---|
| 编程范式 | 面向过程 / 传统函数式 | 面向对象 (OOP) |
| 代码组织 | 一个函数通常只有一个入口,多接口需要内部写路由(如使用 uni-cloud-router) |
一个对象包含多个方法,每个方法自然对应一个接口,天然内聚 |
| 前端调用方式 | uniCloud.callFunction({ name, data }) |
const obj = uniCloud.importObject('name'); obj.method() |
| 参数传递 | 所有参数打包放在一个 event 对象中 |
像写普通 JavaScript 一样,支持多参数按顺序传递 |
| IDE 支持 | HBuilderX 无法自动提示参数和方法名 | HBuilderX 提供代码自动补全,前端输入方法名时有极佳的提示 |
| 错误处理 | 需要自己在回调或 then 中判断业务状态码 |
支持标准的 try-catch 捕获云端抛出的异常 |
| 适用场景 | 独立逻辑、定时任务、微信/支付宝支付异步回调、URL 化的 HTTP 接口 | 复杂的业务模块(如文章管理、用户中心、商城购物车等全套 CRUD) |
四、 总结与选型建议
- 优先使用云对象: 对于 2022 年以后开发的新项目,绝大多数的前后端交互业务 (凡是需要前端点击、加载并向后端请求数据的场景),都应该首选云对象。它能让你的代码少写 30% 以上的胶水代码,且后期维护体验极佳。
- 特殊场景使用云函数: 只有当遇到定时任务(Timer)、数据库触发器(DB Trigger)、或者是接收第三方服务器的 Webhook 回调(如微信支付成功的通知通知,需要配置云函数 URL 化)时,才使用传统的云函数。
unicloud 云数据库
学习 uniCloud 云数据库(下面简称"云数据库"),可以说是掌握 uni-app 全栈开发的"核心通关钥匙"。
uniCloud 数据库底层基于 MongoDB ,是一个 NoSQL(非关系型)文档数据库。对于初学者来说,不要被各种专业术语吓到,我们可以通过"换脑"对比和三大核心概念,带你快速通关。
一、 快速换脑:传统数据库 VS 云数据库
如果你以前了解过传统的关系型数据库(如 MySQL),可以通过下面的映射表快速理解云数据库的结构:
| 传统关系型数据库 (如 MySQL) | uniCloud 云数据库 (NoSQL) | 概念解释 |
|---|---|---|
| 数据库 (Database) | 服务空间 (Space) | 独立的项目数据隔离区域。 |
| 数据表 (Table) | 集合 (Collection) | 存放同类数据的容器(如用户表、商品表)。 |
| 行 / 记录 (Row / Record) | 文档 (Document) | 具体的一条数据,表现形式就是一个 JSON 对象。 |
| 列 / 字段 (Column / Field) | 字段 (Field) | JSON 对象中的各种属性(键值对)。 |
在云数据库中,一条典型的数据(文档)长这样,完全就是你熟悉的 JSON:
json
{
"_id": "60a76f23b102900001096a12",
"username": "张三",
"age": 18,
"tags": ["前端", "uni-app"]
}
注意: 每一条记录都会自动生成一个全球唯一的字符串
_id,作为这条数据的唯一标识。
二、 核心主线:uniCloud 的两大开发模式
在学习云数据库时,最容易让新人懵圈的是:"我到底应该在前端写数据库代码,还是在**后端(云函数/云对象)**写?"
答案是:uniCloud 两种都支持,但目前业界强烈推荐使用 ClientDB 模式。
1. 传统模式(云端调用)
- 流程:前端 -> 请求云对象 -> 云对象操作数据库 -> 返回给前端。
- 特点:安全,但比较繁琐,增删改查都要写一堆重复的后端代码。
2. ClientDB 模式(前端直连模式------uniCloud的灵魂)
- 流程 :前端 -> 直接读写数据库。
- 特点:你不需要写任何一句话后端代码!直接在前端页面里用一行组件或者 JS 代码就能把数据库里的数据显示出来。
- 疑问 :前端直接读写数据库,那用户不就可以随便篡改别人的数据了?安全怎么保证?------ 这就要引入 uniCloud 的核心护城河:DB Schema。
三、 三大核心修炼模块(JQL、Schema、组件)
想要精通云数据库,你需要攻克以下三个核心技术点:
1. DB Schema(数据库安全与规则验证)
当你创建一张表(集合)时,uniCloud 要求你编写一个 .schema.json 的配置文件。它是这张表的"保安"。 它负责两件事:
- 权限控制 (Permission) :谁能读?谁能写?(例如:
"read": "auth.uid != null"表示只有登录用户才能读取数据)。 - 数据校验 (Validator) :字段类型对不对?是不是必填?(例如:手机号格式是否正确)。
只要写好 Schema,前端直连数据库就是绝对安全的。
2. JQL(JavaScript 查询语言)
传统 MongoDB 的查询语句非常晦涩难懂。为此,DCloud 研发了 JQL 。它让你用写 JavaScript 的思维去查询数据库,甚至连联表查询(同时查订单表和用户表)都简单得令人发指。
-
传统 MongoDB 语法: 晦涩、嵌套深。
-
JQL 语法示例(前端直连查询):
kotlinconst db = uniCloud.database(); // 查询 book 表中,作者是"张三"且价格大于50的书,只要书名和价格,按价格倒序排 db.collection('book') .where('author == "张三" && price > 50') .field('title, price') .orderBy('price desc') .get() .then(res => { console.log(res.result.data); });
3. 页面组件,0代码渲染
为了进一步解放前端工程师,uniCloud 甚至把 JQL 封装成了前端组件。你连上面的 JS 代码都不用写,直接在 HTML 模板里挂载组件:
xml
<template>
<view>
<unicloud-db v-slot:default="{data, loading, error}" collection="book" where="price > 50">
<view v-if="loading">加载中...</view>
<view v-else v-for="item in data" :key="item._id">
书名:{{ item.title }} ------ 价格:{{ item.price }}
</view>
</unicloud-db>
</view>
</template>
四、 新手学习路线建议
- 第一步:去控制台建表
登录 uniCloud 控制台,或者在 HBuilderX 中新建一个云数据库集合。记得勾选"使用内置模板"(比如选一个 uni-id-users 或者 opendb-news-articles 新闻表),观察它们的 Schema 是怎么写的。
- 第二步:尝试用 unicloud-db 组件拉取数据
在前端页面里,用上面提到的组件尝试把表里的数据在界面上渲染出来,感受 ClientDB 的便利。
- 第三步:学习 JQL 的增删改查 API
掌握如何在前端通过 JS 代码触发 db.collection().add()、remove()、update()。
第四步:进阶联表查询 (uni-id 关联)
学习如何通过 JQL 把"文章表"和"用户表"关联,直接查出文章的同时拿到作者的昵称和头像。
云存储
系统地学习 uniCloud 云存储 ,其实比学习云数据库要轻松得多。它的核心概念非常纯粹:上传、下载、删除、获取临时链接。
为了帮你快速通关云存储,我们可以把学习路线拆解为四个阶段:核心 API 体系、上传策略、高阶进阶技巧、以及一个完整的实战闭环。
第一阶段:核心 API 体系(文件的"增删改查")
在 uniCloud 中,管理文件主要依靠以下 4 个出镜率最高的 API:
-
uniCloud.uploadFileuniCloud.uploadFile(上传)- 作用:把手机本地的临时文件(如相册图片、拍摄的视频)推送到云端。
-
uniCloud.getTempFileURLuniCloud.getTempFileURL(获取临时下载链接)- 作用 :如果你的文件设置了权限(非公开),前端直接用
fileID无法查看,需要用这个 API 换取一个带有时效性(如 1 小时有效)的普通 HTTPS 链接。
- 作用 :如果你的文件设置了权限(非公开),前端直接用
-
uniCloud.downloadFileuniCloud.downloadFile(下载)- 作用:把云端的文件下载到手机本地,通常用于文件预览(如查看 PDF、下载安装包)。
-
uniCloud.deleteFileuniCloud.deleteFile(删除)- 作用 :当用户删除了某条商品或换了头像,一定要记得用它把旧文件从云存储里删掉,否则死文件会一直占用你的云存储空间并持续计费。
第二阶段:上传策略选择(前端直传 VS 云端上传)
在实际开发中,文件可以从"前端"直接传给云存储,也可以先传给"云函数",再由云函数传给云存储。
| 策略 | 运行流程 | 优缺点与适用场景 |
|---|---|---|
| 前端直传 (强烈推荐) | 前端 \rightarrow 云存储 | 优点 :速度极快,不占用云函数运行时间(省钱),支持监听上传进度。 适用场景:用户传头像、发朋友圈传图片、上传小视频等 95% 的场景。 |
| 云端上传 (特殊场景) | 前端 \rightarrow 云函数 \rightarrow 云存储 | 优点 :可以在云端对文件进行加解密、安全合规检查或利用代码自动生成文件(如生成 PDF 报告、Excel 报表)。 适用场景:服务器端动态生成文件、不允许前端知晓的敏感文件操作。 |
第三阶段:高阶进阶技巧(避坑与实战必备)
如果你想在实际项目里用好云存储,必须掌握以下三个进阶点:
1. 规范的路径与文件名规划
千万不要把所有文件都直接扔在根目录下,也不要使用原文件名(容易重名覆盖)。
- 推荐做法 :按照 "功能模块/日期/用户ID_时间戳.扩展名" 的格式命名。
- 示例 :
cloudPath: 'avatars/202606/user_9958_' + Date.now() + '.jpg'。这样在控制台后台查看时一目了然。
2. 阿里云/腾讯云的"图片处理"大招
uniCloud 无论是阿里云还是腾讯云,其底层存储(OSS/COS)都自带了强大的图片后处理功能 。你不需要在前端压缩图片,只需要在图片的 URL 后面加上特定参数,就能实现裁剪、缩放、甚至加水印。
- 阿里云示例 :在图片链接后加上
?x-oss-process=image/resize,m_fill,w_100,h_100,云端会自动返回一张 100 \times 100 的裁剪后缩略图,极大地节省用户的手机流量。
3. 严格的内容安全检测(防封必看)
如果你的应用允许用户公开发布图片(如社区、评论区),上线前必须接入安全审核。
- 可以使用 uniCloud 官方扩展能力
uni-sec-check。 - 流程:前端选图 \rightarrow 调用云对象 \rightarrow 云对象调用安全审核 API \rightarrow 审核通过后再允许写入数据库并展示。
第四阶段:完整实战闭环(上传头像并更新数据库)
下面是一个标准的用户修改头像的业务逻辑,包含了选择图片 \rightarrow 上传云存储 \rightarrow 更新数据库的完整闭回代码:
javascript
// 假设这是一个修改头像的方法
async function changeAvatar() {
// 1. 让用户选择一张相册图片
const [chooseErr, chooseRes] = await uni.chooseImage({ count: 1 });
if (chooseErr) return;
const localPath = chooseRes.tempFilePaths[0];
const fileExtension = localPath.substring(localPath.lastIndexOf('.')); // 获取后缀名,如 .jpg
uni.showLoading({ title: '上传中...' });
try {
// 2. 将图片上传到云存储
const uploadRes = await uniCloud.uploadFile({
filePath: localPath,
cloudPath: `user_avatars/${Date.now()}${fileExtension}` // 规整的云端路径
});
const fileID = uploadRes.fileID; // 拿到云端唯一标识
// 3. 呼叫云对象,把这个 fileID 存入当前登录用户的数据库表里
const userCo = uniCloud.importObject('user-center');
await userCo.updateUserAvatar({ avatarUrl: fileID });
uni.showToast({ title: '头像修改成功!', icon: 'success' });
} catch (error) {
console.error('修改头像失败:', error);
uni.showToast({ title: '上传失败', icon: 'none' });
} finally {
uni.hideLoading();
}
}
云数据库中users.init_data.json和jql
users.init_data.json 和 JQL 都是 uniCloud 云数据库体系里的重要功能,一个管"数据初始化",一个管"数据查询",下面分别说下它们的作用。
1. users.init_data.json 是用来干嘛的?
它是 users 表(用户表)的初始化数据文件,属于 uniCloud 的"数据库初始化"机制。
-
存放位置 :通常在
uniCloud/database/目录下,文件名格式为{表名}.init_data.json。比如users.init_data.json就是给users表准备的初始数据。 -
内容格式 :一个 JSON 数组,里面是要预设的数据记录。
json[{ "_id": "admin-account-01", "username": "admin", "password": "密码的加密结果", "role": ["admin"] }] -
什么时候生效 :
- 在 HBuilderX 中,通过 "上传所有数据表结构及数据" 或 "初始化云数据库" 命令部署时,uniCloud 会把这个文件里的数据插入到
users表中。 - 通常用来创建预设账号(如初始管理员)、默认角色等。比如 uni-id 体系里,你可能需要先有一个管理员用户,用这个文件就能自动创建,不用手动去加。
- 在 HBuilderX 中,通过 "上传所有数据表结构及数据" 或 "初始化云数据库" 命令部署时,uniCloud 会把这个文件里的数据插入到
注意:它只在首次插入或按规则覆盖时起作用,已经存在的数据不会被随意覆盖,具体行为看你使用的部署选项。
2. JQL 又是干啥的?
JQL (JavaScript Query Language)是 uniCloud 推出的客户端数据库查询语言,让你可以像写 SQL 一样在前端直接操作云数据库,不用每次都写云函数。
-
核心特点:
- 类似 SQL 的语法 ,支持
where、field、orderBy、groupBy、limit等,也支持联表查询(类似关系型数据库的 JOIN)。 - 可直接在客户端(uni-app 前端)使用 ,并自动进行权限校验 (基于
schema里的permission配置),保证数据安全。 - 简化开发,省去大量简单的"增删改查"云函数。
- 类似 SQL 的语法 ,支持
-
使用示例(前端代码):
javascript// 使用 JQL 查询年龄大于 18 的用户,只返回 username 和 avatar const res = await db.collection('users') .where('age > 18') .field('username, avatar') .get() -
它和传统 clientDB 的区别 : JQL 是 clientDB 的查询风格之一,也可以配合
.jql文件使用,或者直接链式调用。最终会被编译成底层 MongoDB 查询指令并执行,同时匹配schema中定义的权限规则(比如"仅本人可读""仅管理员可写"),从而让前端直接操作数据库变得既简单又安全。
一句话总结 :
users.init_data.json 是用来往用户表里塞初始数据 的(比如创建个管理员),而 JQL 是让你在前端就能安全、方便地查数据库的工具,省去了大量手写云函数的重复工作。