uni-app云开发总结
云开发无非就三个概念:云数据库、云函数、云存储
uni-app中新增了一个概念叫做云对象,它其实就是云函数的加强版,它是导出的一个对象,对象中可以包含多个操作数据库的函数,接下来咱们就详细对uni-app的云开发的三部分进行讲解:
一、云数据库知识讲解
uni-app中的云数据库的类型是非关系型数据库 ,那么我们可以回顾一下 关系型数据库 和 非关系型数据库 的区别
云数据库辅助理解(两者区别)
关系型数据库(如MySQL、PostgreSQL)与非关系型数据库(如MongoDB、Redis)的核心区别可总结为以下四大维度,最大区别在于数据模型的灵活性与适用场景:
1. 数据模型(核心差异)
维度 | 关系型数据库 | 非关系型数据库 |
---|---|---|
存储结构 | 表格(行和列),严格预定义Schema | 灵活格式(文档、键值、图等),无固定Schema |
数据关联 | 通过外键实现多表关联(JOIN操作) | 通常无关联,数据内嵌或冗余存储 |
典型场景 | 结构化数据(如订单、用户信息) | 半/非结构化数据(如日志、社交网络) |
存储结构-直观体现:
非关系型:

关系型:

示例对比:
sql
-- 关系型:用户表和订单表分离,通过user_id关联
SELECT * FROM users
JOIN orders ON users.id = orders.user_id;
json
// 非关系型:用户文档内嵌订单数据(MongoDB)
{
"_id": "user123",
"name": "Alice",
"orders": [
{ "orderId": "O1", "amount": 100 },
{ "orderId": "O2", "amount": 200 }
]
}
2. 扩展性与性能
维度 | 关系型数据库 | 非关系型数据库 |
---|---|---|
扩展方式 | 垂直扩展(升级硬件) | 水平扩展(分布式集群) |
读写性能 | 复杂事务下性能较低 | 高并发读写优化(如Redis每秒百万级) |
适用规模 | 中小规模数据 | 海量数据(TB/PB级) |
3. 事务与一致性
维度 | 关系型数据库 | 非关系型数据库 |
---|---|---|
事务支持 | 完整ACID(原子性、一致性、隔离性、持久性) | 部分支持(如MongoDB多文档事务),多数为BASE模型(基本可用、软状态、最终一致性) |
一致性要求 | 强一致性 | 弱一致性(优先可用性和分区容忍性) |
4. 查询与功能
维度 | 关系型数据库 | 非关系型数据库 |
---|---|---|
查询语言 | SQL(结构化查询语言) | 多样化API(如MongoDB的JSON查询) |
索引支持 | B树索引、联合索引 | 灵活索引(如地理位置、全文索引) |
复杂计算 | 支持复杂JOIN和聚合 | 依赖MapReduce或聚合管道 |
如何选择?
-
选关系型:
• 数据结构固定,需要强一致性(如银行交易)。
• 复杂多表关联查询(如ERP系统)。
• 事务密集型场景(如库存扣减)。
-
选非关系型:
• 数据结构多变(如用户行为日志)。
• 高并发读写(如社交平台动态)。
• 水平扩展需求(如物联网海量设备数据)。
一句话总结最大区别
关系型数据库用"表格"锁死结构,保障严谨;非关系型数据库用"自由格式"换取弹性,拥抱变化。
根据业务需求在"严格规范"与"灵活扩展"之间权衡,是现代数据库选型的核心逻辑。
uni-app云数据库解析
在 uni-app 的云开发(uniCloud)中,数据库采用的是基于 JSON 文档的 NoSQL ( 非关系型 )数据库(类似 MongoDB)。以下是 uniCloud 数据库的核心类型概念解析:
1. 数据库类型特点
• 文档型数据库:数据以 JSON 文档 形式存储,无需预定义表结构(Schema),但可通过 Schema 规范数据格式。
• 集合(Collection):相当于关系型数据库中的"表",用于存储一组文档(如 users
集合存储用户数据)。
• 文档(Document):集合中的单条数据记录,格式为 JSON 对象(如一个用户的信息)。
2. 核心数据类型
uniCloud 数据库支持以下基础数据类型:
基本类型
类型 | 说明 | 示例 |
---|---|---|
String | 字符串 | "Hello" |
Number | 数字(整型或浮点型) | 123 或 3.14 |
Boolean | 布尔值 | true 或 false |
Date | 日期对象(存储为时间戳) | new Date() |
Null | 空值 | null |
Undefined | 未定义(通常不建议存储) | undefined |
特殊类型
类型 | 说明 | 示例 |
---|---|---|
GeoPoint | 地理位置点(经纬度) | { type: "Point", coordinates: [经度, 纬度] } |
GeoLineString | 地理路径(多个点连成的线) | { type: "LineString", coordinates: [[lon1, lat1], [lon2, lat2]] } |
Object | 嵌套的 JSON 对象 | { address: { city: "北京", district: "朝阳区" } } |
Array | 数组,可包含混合类型 | ["apple", 123, true] |
Buffer | 二进制数据(如图片、文件) | 通过 new Buffer() 创建 |
3. 特殊字段说明
系统保留字段
字段名 | 说明 |
---|---|
_id |
文档唯一标识(主键),自动生成(可自定义或由系统生成) |
_createTime |
文档创建时间(时间戳,由系统自动维护) |
_updateTime |
文档最后更新时间(时间戳,由系统自动维护) |
_openid |
用户唯一标识(仅限客户端创建文档时自动插入当前用户的 OpenID) |
uid |
开发者自定义的用户 ID(需结合权限系统使用) |
4. 与传统数据库对比
概念 | 关系型数据库(如 MySQL) | uniCloud 数据库(NoSQL) |
---|---|---|
数据单位 | 表(Table) | 集合(Collection) |
数据记录 | 行(Row) | 文档(Document) |
字段类型 | 严格预定义(Schema) | 动态灵活(Schema 可选) |
关联查询 | JOIN 操作 | 嵌套文档或多次查询(非实时关联) |
5. 使用示例
javascript
// 插入一条用户数据到 users 集合
const db = uniCloud.database();
await db.collection('users').add({
name: "John", // String
age: 25, // Number
isAdmin: false, // Boolean
createdAt: new Date(), // Date
location: { // GeoPoint
type: "Point",
coordinates: [116.397428, 39.90923]
},
tags: ["developer", "reader"], // Array
profile: { // Object
bio: "全栈开发者",
website: "https://example.com"
}
});
6. 注意事项
- 类型严格性:查询时需匹配字段类型(如
Number
类型字段不能直接与字符串比较)。 - 地理位置索引:使用地理位置查询前需在 uniCloud 控制台创建 地理位置索引。
- 日期处理:数据库存储的是时间戳,需在客户端转换为
Date
对象。
通过理解这些类型概念,可以更高效地设计 uniCloud 数据库结构和编写查询逻辑。建议结合官方文档进一步实践:uniCloud 数据库文档
二、数据库操作讲解
在 uni-app 云开发中,数据库操作存在两种主要方式:**传统 MongoDB 风格 API(database()
)**和 JQL 查询语言(databaseForJQL()
)。以下是详细对比和操作方式解析:
JQL 是什么?
JQL 是 uniCloud 为简化数据库操作设计的查询语言,融合了 SQL 的易用性和 NoSQL 的灵活性。特点包括:
- 类SQL语法:简化 MongoDB 原生 API 的复杂写法。
- 权限控制:自动校验客户端请求,防止越权操作。
- 跨表查询:支持联表查询(类似 SQL JOIN),突破 NoSQL 单表限制。
- 安全过滤:内置防注入机制,避免恶意代码执行。
在哪里操作?
说了操作云数据库的方式,那么我们应该在哪里去进行操作呐,可以在客户端直接操作 、 云函数操作 、云对象操作 这三个地方进行操作
markdown
┌───────────────┐ ┌───────────────┐
│ 客户端操作 │ │ 服务端操作 │
└───────┬───────┘ └───────┬───────┘
│ │
┌───────────┴───────────┐ ┌─────────┴─────────┐
│ 直接操作数据库 │ │ 通过云函数/云对象│
│ (需安全规则限制) │ │ (拥有管理员权限) │
└───────────┬───────────┘ └─────────┬─────────┘
│ │
┌───────┴───────┐ ┌───────┴───────┐
│ 简单查询/写入 │ │ 复杂业务逻辑 │
│ 低风险操作 │ │ 敏感数据操作 │
└───────────────┘ └───────────────┘
不同位置操作对比表
对比维度 | 客户端直接操作 | 云函数操作 | 云对象操作 |
---|---|---|---|
权限级别 | 受安全规则限制 | 管理员权限 | 管理员权限 |
执行环境 | 用户浏览器/小程序环境 | Node.js 服务端环境 | Node.js 服务端环境 |
网络延迟 | 直连数据库(较快) | 需要两次网络请求 | 需要两次网络请求 |
安全性 | 需严格配置规则 | 天然安全(服务端执行) | 天然安全(服务端执行) |
事务支持 | 不支持 | 支持 | 支持 |
代码复用 | 无法复用 | 通过模块化复用 | 天然支持类方法复用 |
典型场景 | 公开数据查询 | 复杂事务处理 | 业务逻辑封装 |
一、操作方式对比表
1. JQL 核心概念对比(与传统 MongoDB 对比)
对比维度 | database() (传统MongoDB风格) |
databaseForJQL() (JQL查询语言) |
---|---|---|
语法风格 | 链式调用,接近原生MongoDB语法 | 类似SQL的声明式语法,更贴近前端开发习惯 |
联表查询 | 需要手动使用lookup 聚合操作 |
支持自动联表(通过foreignKey 自动关联) |
权限控制 | 依赖安全规则配置 | 内置权限系统,支持动态权限控制 |
事务处理 | 需要显式使用startTransaction |
自动管理事务 |
执行位置 | 客户端/云函数均可执行 | 主要在客户端执行(也可服务端) |
性能优化 | 需要手动优化查询语句 | 自动优化查询计划 |
学习成本 | 需要熟悉MongoDB语法 | 类似SQL的简化语法更易上手 |
官方推荐度 | 基础用法 | 新项目推荐使用 |
2. JQL 核心操作对比(与传统 MongoDB 对比)
操作类型 | JQL 写法 | MongoDB 原生写法 |
---|---|---|
查询单条数据 | db.collection('user').doc('id').get() |
db.user.findOne({ _id: 'id' }) |
条件查询 | db.collection('user').where('age > 20').get() |
db.user.find({ age: { $gt: 20 } }) |
字段过滤 | db.collection('user').field('name,age').get() |
db.user.find({}, { name: 1, age: 1 }) |
联表查询 | 使用 lookup 语法(见下方示例) |
需多次查询或手动聚合 |
分页查询 | db.collection('user').skip(10).limit(5).get() |
db.user.find().skip(10).limit(5) |
二、具体操作方式示例
1. 传统 MongoDB 风格(database()
)
javascript
const db = uniCloud.database()
const cmd = db.command // 操作指令
// 查询
db.collection('articles')
.where({
category: 'tech',
view_count: cmd.gt(1000)
})
.field('title,author')
.orderBy('publish_date', 'desc')
.limit(10)
.get()
// 新增
db.collection('users').add({
name: 'John',
email: '[email protected]',
created_at: Date.now()
})
// 更新
db.collection('orders').doc('order-id').update({
status: 'shipped',
updated_at: Date.now()
})
// 删除
db.collection('logs').doc('log-id').remove()
// 联表查询(需要聚合)
db.collection('orders').aggregate()
.lookup({
from: 'users',
localField: 'user_id',
foreignField: '_id',
as: 'user_info'
})
.end()
2. JQL 查询语言(databaseForJQL()
)
javascript
const db = uniCloud.databaseForJQL()
// 简单查询
db.collection('articles')
.where('category == "tech" && view_count > 1000')
.field('title,author')
.orderBy('publish_date desc')
.limit(10)
.get()
// 自动联表查询(关联users表)
db.collection('articles,users')
.where('articles.author_id == users._id')
.field('articles.title, users.name as author_name')
.get()
// 带权限控制的更新
db.collection('users')
.doc('user-id')
.update({
age: 30
}, {
permission: { write: "auth.uid == targetDoc._id" }
})
// 事务操作(自动管理)
const transaction = await db.startTransaction()
try {
await transaction.collection('accounts')
.doc('account-A')
.update({ balance: db.command.inc(-100) })
await transaction.collection('accounts')
.doc('account-B')
.update({ balance: db.command.inc(100) })
await transaction.commit()
} catch (e) {
await transaction.rollback()
}
三、具体操作位置说明
1. 客户端直接操作(前端代码)
适用场景:
- 简单数据查询(如文章列表)
- 用户自主数据维护(如修改个人资料)
- 低风险数据写入(如评论提交)
代码位置:
js
// 页面/组件的.vue文件中
export default {
methods: {
async loadData() {
const db = uniCloud.databaseForJQL() // 推荐JQL方式
const res = await db.collection('articles')
.where('status == "published"')
.get()
console.log(res)
}
}
}
安全要求:
-
必须配置数据库安全规则
-
禁止开放敏感字段权限
-
示例安全规则:
js{ "read": "doc.status == 'published'", "write": "auth.uid == doc.author_id" }
2. 云函数中操作
适用场景:
- 支付订单处理
- 需要事务的操作(如库存扣减)
- 第三方服务集成(如发送短信)
代码位置:
js
// cloudfunctions/order-function/index.js
exports.main = async (event) => {
const db = uniCloud.database()
const transaction = await db.startTransaction()
try {
// 库存扣减
await transaction.collection('goods')
.doc(event.goodsId)
.update({
stock: db.command.inc(-1)
})
// 生成订单
const orderRes = await transaction.collection('orders').add({
userId: event.uid,
goodsId: event.goodsId,
status: 'created'
})
await transaction.commit()
return orderRes
} catch (e) {
await transaction.rollback()
throw e
}
}
3. 云对象中操作(推荐方式)
适用场景:
- 用户中心功能(注册/登录/资料管理)
- 需要复用逻辑的业务模块
- 需要统一权限控制的场景
代码位置:
js
// cloudobjects/user-center/index.js
module.exports = {
// 统一鉴权中间件
_before() {
const clientInfo = this.getClientInfo()
if (!clientInfo.uniIdToken) {
throw new Error('未授权访问')
}
},
// 用户信息更新方法
async updateProfile(profileData) {
const db = uniCloud.database()
const uid = this.getClientInfo().uid
// 数据校验
if (profileData.age && (profileData.age < 0 || profileData.age > 120)) {
throw new Error('年龄数据异常')
}
return db.collection('users')
.doc(uid)
.update({
...profileData,
updated_at: Date.now()
})
}
}
四、核心差异点解析
1. 联表查询机制
-
传统方式 :需要手动编写聚合管道,使用
lookup
进行多阶段联表 -
JQL方式 :
javascript// 自动联表示例 db.collection('orders,users') .where('orders.user_id == users._id') .field('orders.*, users.name as user_name') .get()
连表查询这里需要注意的是,直接写上面的代码(.where('orders.user_id == users._id')
)时候报错的:说找不到两张之间的关系。这里我们需要配置项目的 表结构/schema,从而设置数据表之间的关系。
场景举例:
场景 :现在有 user 和 **activity **两张数据表,activity 表中的 user_id 对应了 user 表中的 _id
目的 :我现在要查询所有活动 以及对应的发布人信息
表结构配置:
对应的schema文件:
json
{
"bsonType": "object",
"required": [],
"permission": {
"read": true,
"create": true,
"update": true,
"delete": false
},
"properties": {
"_id": {
"description": "ID,系统自动生成",
"foreignKey": "community.activity_id"
},
"user_id": {
"description": "ID,系统自动生成",
"foreignKey": "user._id" // 使用foreignKey表示,此字段关联user表的_id。
}
}
}
通过以上配置以后,咱们就可以进行连表查询了
javascript
const userTemp = db.collection("user")
.getTemp() // 获取临时数据表
const activityTemp = db.collection("activity")
.where("title == '跨区出行'")
.field("user_id,type,title,loscation,content")
.getTemp()
db.collection(activityTemp, userTemp).get()
查询数据:
上面连表查询的"user_id"
字段就会去user表中查找对应的用户数据,
json
[
{
"_id": "67fdcafcf08210c5a2ab7e36",
"content": "乘坐地铁15公里,用时40分钟",
"loscation": "上海市浦东新区",
"title": "跨区出行",
"type": "公共交通",
"user_id": [
{
"_id": "67fdc8d3862066ed97752665",
"carbon_points": 1000,
"create_time": "2025-05-10T14:20:00Z",
"nickname": "蓝天白云",
"openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2N",
"password": "e10adc3949ba59abbe56e057f20f883e",
"phone": "13987654321",
"status": 1,
"total_reduction": 30.800000000000001,
"update_time": "2025-05-11T08:45:00Z",
"user_pic": "https://img0.baidu.com/it/u=306649616,2230355986&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500"
}
]
}
]
2. 权限控制实现
-
传统方式 :依赖数据库安全规则(JSON配置)
json// 安全规则示例 { "read": "doc.status == 'published'", "write": "auth.uid == doc.author_id" }
-
JQL方式 :支持动态权限(代码级控制)
javascriptdb.collection('articles').get({ permission: { read: "doc.status == 'published' || auth.uid == doc.author_id" } })
3. 查询性能优化
-
传统方式 :需要手动创建索引
javascriptdb.createIndex({ collectionName: 'articles', indexes: [{ name: 'category_index', fields: [{ category: 1 }] }] })
-
JQL方式:自动索引建议(控制台提示优化方案)
4. 数据类型处理
-
传统方式 :严格类型校验(需手动处理Date等类型)
javascriptdb.collection('logs').add({ timestamp: new Date().getTime() // 需显式转换 })
-
JQL方式 :自动类型转换
javascriptdb.collection('logs').add({ timestamp: new Date() // 自动转为时间戳 })
五、使用场景建议
推荐使用 database()
的场景:
- 需要复杂聚合查询(如多阶段管道操作)
- 已有MongoDB开发经验的团队
- 需要直接操作数据库指令(如地理位置查询)
推荐使用 databaseForJQL()
的场景:
- 新项目启动(特别是前后端分离架构)
- 需要简化联表查询逻辑
- 希望在前端实现复杂业务逻辑
- 需要动态权限控制的场景
六、混合使用建议
javascript
// 在云函数中结合使用
exports.main = async (event) => {
const db = uniCloud.database()
const jqlDB = uniCloud.databaseForJQL({ clientInfo: event })
// 传统方式处理事务
const transaction = await db.startTransaction()
// JQL方式处理联表查询
const result = await jqlDB.collection('orders,users')
.where('orders.user_id == users._id')
.get()
// 提交事务
await transaction.commit()
return result
}
七、注意事项
-
JQL限制:
- 单次查询最多关联3张表
- 客户端查询最大返回1000条数据
- 复杂聚合仍需使用传统方式
-
迁移成本:
- 现有项目从传统方式迁移到JQL需重写查询逻辑
- 两种方式的数据索引可以复用
-
安全规范:
- JQL客户端查询仍需配置安全规则
- 敏感操作仍需通过云函数/云对象
-
性能监控:
- 控制台可分别查看两种方式的慢查询日志
- JQL查询建议使用
explain()
分析执行计划
javascriptdb.collection('articles').explain().get()
根据项目需求选择合适方案,小型快速开发项目推荐JQL,复杂企业级系统建议两种方式结合使用。
三、云函数与云对象讲解
以下是云函数(Cloud Function)与云对象(Cloud Object)的详细对比
一、核心概念对比
对比维度 | 云函数 (Cloud Function) | 云对象 (Cloud Object) |
---|---|---|
代码组织形式 | 单个函数处理请求 | 类对象封装多个方法 |
调用方式 | uniCloud.callFunction({ name: 'funcName' }) |
uniCloud.importObject('objName').methodName() |
开发范式 | 函数式编程 | 面向对象编程 |
路由机制 | 手动管理(通过函数名区分) | 自动路由(对象方法即接口) |
调用方式对比表
对比维度 | 云函数 (Cloud Function) | 云对象 (Cloud Object) |
---|---|---|
调用入口 | uniCloud.callFunction |
uniCloud.importObject |
参数传递 | 通过 event 对象统一传递 |
直接作为方法参数传递 |
方法调用 | 单入口函数(需自行路由) | 多方法直接调用 |
错误处理 | 需手动捕获异常 | 自动错误冒泡(try-catch 统一处理) |
返回结构 | 需手动包装返回格式 | 自动标准化响应格式 |
类型提示 | 无自动提示 | 支持 JSDoc 类型提示 |
中间件触发 | 需手动实现 | 自动执行 _before 等生命周期方法 |
二、技术特性对比
-
参数处理
-
云函数 ➔ 需手动解析event参数
jsexports.main = async (event) => { const { action, data } = event }
-
云对象 ➔ 自动解析参数(方法直接接收)
jsmodule.exports = { addUser(userData) { /* 直接使用userData */ } }
-
-
错误处理
-
云函数 ➔ 需手动catch错误
jstry { await callFunction('func') } catch(e) {...}
-
云对象 ➔ 自动错误冒泡(客户端自动捕获)
js// 客户端自动接收标准化错误格式
-
-
中间件支持
-
云函数 ➔ 自行实现中间件机制
jsconst auth = require('uni-id').checkToken(event.uniIdToken)
-
云对象 ➔ 内置中间件系统
jsmodule.exports = { _before() { // 统一鉴权逻辑 } }
-
-
类型校验
-
云函数 ➔ 手动校验参数类型
jsif(typeof event.name !== 'string') throw...
-
云对象 ➔ 自动类型校验(基于JSDoc)
js/** * @param {string} userId * @param {number} newAge */ updateAge(userId, newAge) {...}
-
三、功能特性对比
-
代码复用性
-
云函数 ➔ 通过模块化实现
const common = require('./common.js')
-
云对象 ➔ 天然支持继承/混入
-
js
class BaseObject { ... }
module.exports = class User extends BaseObject {...}
-
调试支持
- 云函数 ➔ 需要模拟event参数
- 云对象 ➔ 支持方法级断点调试
-
文档生成
- 云函数 ➔ 手动维护接口文档
- 云对象 ➔ 自动生成API文档(基于JSDoc)
-
性能表现
- 云函数 ➔ 单个函数独立冷启动
- 云对象 ➔ 对象级缓存(方法调用共享上下文)
四、生命周期对比
markdown
云函数生命周期:
客户端调用 ➔ 创建实例 ➔ 执行main函数 ➔ 销毁实例
云对象生命周期:
客户端调用 ➔ 创建对象实例 ➔ 执行中间件 ➔ 执行目标方法 ➔ 保持常驻(可复用)
五、最佳实践对比
场景 | 推荐方案 | 示例 |
---|---|---|
简单原子操作 | 云函数 | 发送短信验证码 |
复杂业务逻辑 | 云对象 | 订单创建(涉及多表操作) |
高频调用接口 | 云对象(常驻内存) | 实时聊天消息处理 |
需要严格权限控制 | 云对象(中间件统一处理) | 支付操作 |
第三方服务对接 | 云函数 | 微信支付回调处理 |
六、代码结构对比
云函数典型结构
javascript
// cloudfunctions/user-function/index.js
exports.main = async (event, context) => {
const { action, data } = event
switch(action) {
case 'addUser':
return addUser(data)
case 'deleteUser':
return deleteUser(data)
default:
throw new Error('Invalid action')
}
}
function addUser(userData) { /* ... */ }
function deleteUser(userId) { /* ... */ }
云对象典型结构
javascript
// cloudobjects/user-object/index.js
module.exports = {
// 前置中间件
_before() {
this.verifyToken() // 统一鉴权
},
/**
* 添加用户
* @param {Object} userData 用户数据
*/
async addUser(userData) {
// 业务逻辑
},
/**
* 删除用户
* @param {string} userId 用户ID
*/
async deleteUser(userId) {
// 业务逻辑
},
// 私有方法(不对外暴露)
verifyToken() {
// 鉴权逻辑
}
}
七、迁移路径建议
markdown
传统云函数 ➔ 云对象演进路线:
1. 拆分功能模块 → 2. 封装业务对象 → 3. 添加中间件 → 4. 增加类型校验 → 5. 实现方法复用
关键结论:
- 新项目优先使用云对象(架构更清晰、维护成本低)
- 存量项目逐步迁移(混合使用两种方案)
- 性能敏感场景评估使用(云对象常驻内存 vs 云函数独立实例)
- 复杂业务必用云对象(继承/中间件/类型校验等特性优势明显)
通过对比可以看出,云对象在代码组织、开发效率和可维护性方面具有显著优势,而云函数在简单场景和特殊需求场景仍保有其适用价值。
四、云存储讲解
1. 云存储是什么?
云存储是uniCloud提供的文件存储服务,类似于"云端硬盘",开发者可以快速上传、下载、管理文件(如图片、视频、文档等) ,无需自建文件服务器。
核心特点:
- 免运维:无需配置服务器或CDN,开箱即用。
- 权限控制:通过安全规则限制文件访问权限。
- 自动生成链接:上传后自动返回文件URL,可直接用于前端展示。
- 与数据库联动:文件ID可与云数据库关联,实现文件元数据管理。
以下是对 uni-app 云开发中 云存储(Cloud Storage) 的详细知识点讲解,采用结构化方式呈现:
一、核心功能概述
markdown
1. **文件全生命周期管理**
- 上传 → 存储 → 处理 → 下载 → 删除
2. **多端统一API**
- 支持Web/H5、小程序、App全平台
3. **CDN加速**
- 自动全球分发,提升访问速度
4. **权限控制体系**
- 支持「公有读/私有」两种访问模式
5. **文件处理能力**
- 图片压缩、裁剪、水印
- 视频截图、音频转码(需配置扩展)
二、核心操作API及示例
操作 | 方法示例 | 说明 |
---|---|---|
上传文件 | uniCloud.uploadFile() |
客户端或云函数上传文件到云存储 |
下载文件 | uniCloud.downloadFile() |
根据文件ID下载到本地临时路径 |
删除文件 | uniCloud.deleteFile() |
通过文件ID删除云端文件 |
获取文件列表 | uniCloud.getTempFileList() |
查询存储桶中的文件列表(需云函数调用) |
1. 文件上传(重点)
基础上传:
javascript
// 选择文件
const res = await uni.chooseImage({ count: 1 })
const tempFile = res.tempFiles[0]
// 执行上传
const uploadRes = await uniCloud.uploadFile({
filePath: tempFile.path,
cloudPath: `user_avatar/${Date.now()}.jpg`, // 云端路径
onUploadProgress: (e) => {
console.log(`上传进度: ${e.progress}%`)
}
})
// 注意:这里的uploadRes.fileID就可以在HTML中访问了,但是最好用uniCloud.getTempFileURL转化为HTTPS 可访问URL
console.log('文件ID:', uploadRes.fileID)
高级特性:
-
分片上传 (大文件自动处理)
javascriptuniCloud.uploadFile({ filePath: largeFile.path, cloudPath: 'bigfile.zip', uploadChunked: true // 启用分片 })
-
自定义metadata :
javascriptuploadFile({ filePath: file.path, cloudPath: 'data.json', fileMeta: { // 自定义元数据 category: 'config', version: '1.0' } })
2. 文件下载
javascript
// 公有读文件直接使用URL
const publicUrl = 'cloud://prod-env.7072-prod-env-1303011235/user_avatar/1.jpg'
// 私有文件需获取临时链接
const downloadRes = await uniCloud.downloadFile({
fileID: 'cloud://prod-env.7072-prod-env-1303011235/private/file.txt'
})
console.log('临时路径:', downloadRes.tempFilePath)
3. 文件删除
js
// 删除图片
const handleDelete = (fileID, index) => {
uni.showModal({
title: '确认删除',
content: '确定要删除这张图片吗?',
success: async (res) => {
if (res.confirm) {
try {
const result = await active.deleteFile(fileID)
if (result.errCode === 0) {
fileIDs.value.splice(index, 1)
uni.showToast({
title: '删除成功'
})
}
} catch (err) {
uni.showToast({
title: `删除失败: ${err.message}`,
icon: 'none'
})
}
}
}
})
}
配套云对象代码:
js
// 删除活动图片
async deleteFile(fileID) {
// 参数校验
if (!fileID) {
return {
errCode: 400,
errMsg: '缺少fileID参数'
}
}
try {
// 实际删除操作
const result = await uniCloud.deleteFile({
fileList: fileID
})
return {
errCode: 0,
data: result
}
} catch (error) {
return {
errCode: 500,
errMsg: '文件删除失败: ' + error.message,
error: error
}
}
},
4. 文件管理
javascript
const result = await uniCloud.getTempFileURL({
fileList: ['cloud://xxx.jpg'] // 获取临时URL
})
await uniCloud.deleteFile({
fileList: ['cloud://obsolete.jpg'] // 批量删除
})
const listRes = await uniCloud.listFiles({
prefix: 'user_avatar/', // 目录前缀
limit: 100 // 分页大小
})
三、权限控制体系
云存储通过 安全规则(Security Rules) 实现精细化权限管理,规则基于 JSON 配置,在 uniCloud
控制台中设置。权限验证发生在文件操作(读/写/删除)时,由云端自动执行。
1. 权限模式
权限类型 | 访问规则 | 典型场景 |
---|---|---|
公有读 | 任何人可读,不可写 | 网站图片/公开文档 |
私有 | 需通过云函数/云对象获取临时URL | 用户私有文件/敏感数据 |
2. 权限配置方式
通过文件路径前缀控制:
bash
cloud://env-id.7072-env-id-1303011235/ # 根目录
├─ public/ # 公有读目录
└─ private/ # 私有目录
动态权限管理(云函数中):
javascript
// 生成带时效的下载链接
const getSecureURL = async (fileID) => {
return uniCloud.getTempFileURL({
fileList: [fileID],
expire: 3600 // 1小时有效
})
}
四、文件处理能力
1. 图片处理(URL参数方式)
javascript
// 原图:cloud://env-id.7072-env-id-1303011235/photo.jpg
const processedURL = originalURL + '?imageMogr2/thumbnail/300x300'
// 组合操作示例:
// 缩略图 + 圆形裁剪 + 水印
const complexURL = originalURL +
'?imageMogr2/thumbnail/200x200' +
'|circle/radius/!50p' +
'|watermark/2/text/5paw5LiJ5Y-R/image/aHR0cHM6Ly9...'
2. 视频处理(需扩展)
javascript
// 获取视频封面
const videoCoverURL = videoFileID + '?vframe/jpg/offset/5'
// 视频转码(HLS格式)
const hlsURL = videoFileID + '?transcode/hls'
五、安全防护策略
markdown
1. **上传防护**
- 文件类型白名单(MIME类型检查)
- 文件大小限制(单文件≤100MB)
- 病毒扫描(需集成安全能力)
2. **访问控制**
- 私有文件临时URL时效性(默认1小时)
- 防盗链设置(Referer白名单)
3. **存储安全**
- 自动多副本存储
- 跨地域容灾备份
4. **监控预警**
- 异常流量告警
- 敏感文件操作日志
六、最佳实践示例
这里给出一个用户头像上传的例子,帮助理解云存储的使用方法
1. 用户头像上传方案
1.1 选择并上传头像(前端)
html
<template>
<view class="container">
<!-- 头像展示 -->
<image :src="avatarUrl" mode="aspectFill" @click="chooseAvatar" />
<!-- 上传按钮 -->
<button @click="uploadAvatar">确认上传</button>
</view>
</template>
<script>
export default {
data() {
return {
tempFilePath: '', // 临时文件路径
avatarUrl: '', // 头像网络URL
userId: '' // 当前用户ID(可从uni-id获取)
}
},
onLoad() {
this.userId = uni.getStorageSync('uni_id') || ''; // 获取当前用户ID
this.loadUserAvatar(); // 加载已有头像
},
methods: {
// 选择图片
chooseAvatar() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
success: (res) => {
this.tempFilePath = res.tempFilePaths[0];
}
});
},
// 上传到云存储
async uploadAvatar() {
if (!this.tempFilePath) return uni.showToast({ title: '请选择图片', icon: 'none' });
uni.showLoading({ title: '上传中...' });
try {
// 1. 上传到云存储(路径格式:avatars/{userId}/timestamp.jpg)
const cloudPath = `avatars/${this.userId}/${Date.now()}.jpg`;
const uploadRes = await uniCloud.uploadFile({
filePath: this.tempFilePath,
cloudPath: cloudPath
});
// 注意:这里的uploadRes.fileID就可以在HTML中访问了,但是最好用uniCloud.getTempFileURL转化为HTTPS 可访问URL
// 2. 将 fileID 存入用户表(关联头像)
const db = uniCloud.database();
await db.collection('uni-id-users').doc(this.userId).update({
avatar: uploadRes.fileID // 存储云存储文件ID
});
// 3. 更新本地头像显示
this.avatarUrl = await this.getFileUrl(uploadRes.fileID);
uni.showToast({ title: '上传成功' });
} catch (e) {
uni.showToast({ title: '上传失败: ' + e.message, icon: 'none' });
} finally {
uni.hideLoading();
}
},
// 加载用户已有头像
async loadUserAvatar() {
const db = uniCloud.database();
const userRes = await db.collection('uni-id-users').doc(this.userId).get();
if (userRes.data[0]?.avatar) {
this.avatarUrl = await this.getFileUrl(userRes.data[0].avatar);
}
},
// 将 cloud://fileID 转为 HTTPS 可访问URL
async getFileUrl(fileID) {
const { result } = await uniCloud.getTempFileURL({ fileList: [fileID] });
return result.fileList[0].tempFileURL;
}
}
}
</script>
<style>
image {
width: 150rpx;
height: 150rpx;
border-radius: 50%;
}
</style>
1.2. 云函数(可选)
如果需要更复杂的逻辑(如图片压缩、敏感内容检测),可增加云函数处理:
javascript
// 云函数入口文件(cloudfunctions/avatar-processor/index.js)
exports.main = async (event, context) => {
const { fileID, userId } = event;
// 示例:调用图片压缩API
const result = await uniCloud.downloadFile({ fileID });
const compressedPath = await imageCompress(result.fileContent);
// 重新上传压缩后的图片
const newFile = await uniCloud.uploadFile({
filePath: compressedPath,
cloudPath: `avatars/${userId}/compressed_${Date.now()}.jpg`
});
return { fileID: newFile.fileID };
};
// 简易图片压缩(实际需调用三方服务或使用sharp库)
async function imageCompress(buffer) {
// ...实现压缩逻辑
}
2. 大文件分片上传优化
javascript
// 自定义分片策略
uniCloud.uploadFile({
filePath: largeFile.path,
cloudPath: 'bigfile.zip',
uploadChunked: true,
chunkSize: 2 * 1024 * 1024, // 2MB分片
onChunkUpload: ({ progress, chunkIndex }) => {
console.log(`分片${chunkIndex}上传完成`)
}
})
七、调试与监控
1. 开发阶段调试
javascript
// 查看文件元数据
const metadata = await uniCloud.getFileInfo({
fileList: [fileID]
})
console.log('文件信息:', metadata)
// 本地文件模拟上传
uniCloud.uploadFile({
fileContent: new Buffer.from('test content'), // Node环境可用
cloudPath: 'test.txt'
})
2. 生产环境监控项
监控维度 | 检查指标 | 告警阈值 |
---|---|---|
存储量 | 总存储空间使用率 | ≥80% |
流量 | CDN下行流量突增 | 环比增长≥300% |
请求数 | 异常404请求量 | 每分钟≥100次 |
安全事件 | 病毒文件上传次数 | 单日≥1次 |
关键结论:
-
路径规划原则
- 按业务类型分目录(如
/user_upload/
、/system_config/
) - 使用时间戳/UUID防止文件名冲突
- 按业务类型分目录(如
-
性能优化重点
- 前端压缩(减少传输量)
- CDN缓存策略(合理设置Cache-Control)
- 异步处理机制(大文件后台处理)
-
安全必做项
- 设置上传文件类型白名单
- 私有文件必须设置访问时效
- 定期审计存储桶权限
-
成本控制技巧
- 开启低频存储类型
- 设置生命周期自动删除临时文件
- 使用图片处理减少存储冗余
}.jpg`
});
return { fileID: newFile.fileID };
};
// 简易图片压缩(实际需调用三方服务或使用sharp库)
async function imageCompress(buffer) {
// ...实现压缩逻辑
}
#### 2. 大文件分片上传优化
```javascript
// 自定义分片策略
uniCloud.uploadFile({
filePath: largeFile.path,
cloudPath: 'bigfile.zip',
uploadChunked: true,
chunkSize: 2 * 1024 * 1024, // 2MB分片
onChunkUpload: ({ progress, chunkIndex }) => {
console.log(`分片${chunkIndex}上传完成`)
}
})
七、调试与监控
1. 开发阶段调试
javascript
// 查看文件元数据
const metadata = await uniCloud.getFileInfo({
fileList: [fileID]
})
console.log('文件信息:', metadata)
// 本地文件模拟上传
uniCloud.uploadFile({
fileContent: new Buffer.from('test content'), // Node环境可用
cloudPath: 'test.txt'
})
2. 生产环境监控项
监控维度 | 检查指标 | 告警阈值 |
---|---|---|
存储量 | 总存储空间使用率 | ≥80% |
流量 | CDN下行流量突增 | 环比增长≥300% |
请求数 | 异常404请求量 | 每分钟≥100次 |
安全事件 | 病毒文件上传次数 | 单日≥1次 |
关键结论:
-
路径规划原则
- 按业务类型分目录(如
/user_upload/
、/system_config/
) - 使用时间戳/UUID防止文件名冲突
- 按业务类型分目录(如
-
性能优化重点
- 前端压缩(减少传输量)
- CDN缓存策略(合理设置Cache-Control)
- 异步处理机制(大文件后台处理)
-
安全必做项
- 设置上传文件类型白名单
- 私有文件必须设置访问时效
- 定期审计存储桶权限
-
成本控制技巧
- 开启低频存储类型
- 设置生命周期自动删除临时文件
- 使用图片处理减少存储冗余
通过合理使用云存储能力,结合uni-app的多端特性,可以构建高效安全的文件管理系统。建议结合uni-admin进行可视化文件管理,并定期使用listFiles
API进行存储空间审计。