uni-app云开发总结
uni-app云开发总结
云开发无非就三个概念:云数据库、云函数、云存储
uni-app中新增了一个概念叫做云对象,它其实就是云函数的加强版,它是导出的一个对象,对象中可以包含多个操作数据库的函数,接下来咱们就详细对uni-app的云开发的三部分进行讲解:
一、云数据库知识讲解
uni-app中的云数据库的类型是非关系型数据库,那么我们可以回顾一下 关系型数据库 和 非关系型数据库 的区别
云数据库辅助理解(两者区别)
关系型数据库(如MySQL、PostgreSQL)与非关系型数据库(如MongoDB、Redis)的核心区别可总结为以下四大维度,最大区别在于数据模型的灵活性与适用场景:
1. 数据模型(核心差异)
维度 | 关系型数据库 | 非关系型数据库 |
---|---|---|
存储结构 | 表格(行和列),严格预定义Schema | 灵活格式(文档、键值、图等),无固定Schema |
数据关联 | 通过外键实现多表关联(JOIN操作) | 通常无关联,数据内嵌或冗余存储 |
典型场景 | 结构化数据(如订单、用户信息) | 半/非结构化数据(如日志、社交网络) |
存储结构-直观体现:
非关系型:
关系型:
示例对比:
-- 关系型:用户表和订单表分离,通过user_id关联
SELECT * FROM users
JOIN orders ON users.id = orders.user_id;
// 非关系型:用户文档内嵌订单数据(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. 使用示例
// 插入一条用户数据到 users 集合
const db = uniCloud.database();
await db.collection('users').add({name: "John", // Stringage: 25, // NumberisAdmin: false, // BooleancreatedAt: new Date(), // Datelocation: { // GeoPointtype: "Point",coordinates: [116.397428, 39.90923]},tags: ["developer", "reader"], // Arrayprofile: { // Objectbio: "全栈开发者",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 单表限制。
- 安全过滤:内置防注入机制,避免恶意代码执行。
在哪里操作?
说了操作云数据库的方式,那么我们应该在哪里去进行操作呐,可以在客户端直接操作、 云函数操作、云对象操作 这三个地方进行操作
┌───────────────┐ ┌───────────────┐│ 客户端操作 │ │ 服务端操作 │└───────┬───────┘ └───────┬───────┘│ │┌───────────┴───────────┐ ┌─────────┴─────────┐│ 直接操作数据库 │ │ 通过云函数/云对象││ (需安全规则限制) │ │ (拥有管理员权限) │└───────────┬───────────┘ └─────────┬─────────┘│ │┌───────┴───────┐ ┌───────┴───────┐│ 简单查询/写入 │ │ 复杂业务逻辑 ││ 低风险操作 │ │ 敏感数据操作 │└───────────────┘ └───────────────┘
不同位置操作对比表
对比维度 | 客户端直接操作 | 云函数操作 | 云对象操作 |
---|---|---|---|
权限级别 | 受安全规则限制 | 管理员权限 | 管理员权限 |
执行环境 | 用户浏览器/小程序环境 | 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()
)
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: 'john@example.com',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()
)
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. 客户端直接操作(前端代码)
适用场景:
- 简单数据查询(如文章列表)
- 用户自主数据维护(如修改个人资料)
- 低风险数据写入(如评论提交)
代码位置:
// 页面/组件的.vue文件中
export default {methods: {async loadData() {const db = uniCloud.databaseForJQL() // 推荐JQL方式const res = await db.collection('articles').where('status == "published"').get()console.log(res)}}
}
安全要求:
-
必须配置数据库安全规则
-
禁止开放敏感字段权限
-
示例安全规则:
{"read": "doc.status == 'published'","write": "auth.uid == doc.author_id" }
2. 云函数中操作
适用场景:
- 支付订单处理
- 需要事务的操作(如库存扣减)
- 第三方服务集成(如发送短信)
代码位置:
// 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. 云对象中操作(推荐方式)
适用场景:
- 用户中心功能(注册/登录/资料管理)
- 需要复用逻辑的业务模块
- 需要统一权限控制的场景
代码位置:
// 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方式:
// 自动联表示例 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文件:
{"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。}}
}
通过以上配置以后,咱们就可以进行连表查询了
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表中查找对应的用户数据,
[{"_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配置)
// 安全规则示例 {"read": "doc.status == 'published'","write": "auth.uid == doc.author_id" }
- JQL方式:支持动态权限(代码级控制)
db.collection('articles').get({permission: { read: "doc.status == 'published' || auth.uid == doc.author_id"} })
3. 查询性能优化
- 传统方式:需要手动创建索引
db.createIndex({collectionName: 'articles',indexes: [{ name: 'category_index', fields: [{ category: 1 }] }] })
- JQL方式:自动索引建议(控制台提示优化方案)
4. 数据类型处理
- 传统方式:严格类型校验(需手动处理Date等类型)
db.collection('logs').add({timestamp: new Date().getTime() // 需显式转换 })
- JQL方式:自动类型转换
db.collection('logs').add({timestamp: new Date() // 自动转为时间戳 })
五、使用场景建议
推荐使用 database()
的场景:
- 需要复杂聚合查询(如多阶段管道操作)
- 已有MongoDB开发经验的团队
- 需要直接操作数据库指令(如地理位置查询)
推荐使用 databaseForJQL()
的场景:
- 新项目启动(特别是前后端分离架构)
- 需要简化联表查询逻辑
- 希望在前端实现复杂业务逻辑
- 需要动态权限控制的场景
六、混合使用建议
// 在云函数中结合使用
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()
分析执行计划
db.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参数
exports.main = async (event) => {const { action, data } = event }
-
云对象 ➔ 自动解析参数(方法直接接收)
-
module.exports = {addUser(userData) { /* 直接使用userData */ } }
-
-
错误处理
- 云函数 ➔ 需手动catch错误
try { await callFunction('func') } catch(e) {...}
- 云对象 ➔ 自动错误冒泡(客户端自动捕获)
// 客户端自动接收标准化错误格式
- 云函数 ➔ 需手动catch错误
-
中间件支持
- 云函数 ➔ 自行实现中间件机制
const auth = require('uni-id').checkToken(event.uniIdToken)
- 云对象 ➔ 内置中间件系统
module.exports = {_before() { // 统一鉴权逻辑 } }
- 云函数 ➔ 自行实现中间件机制
-
类型校验
- 云函数 ➔ 手动校验参数类型
if(typeof event.name !== 'string') throw...
- 云对象 ➔ 自动类型校验(基于JSDoc)
/*** @param {string} userId* @param {number} newAge*/ updateAge(userId, newAge) {...}
- 云函数 ➔ 手动校验参数类型
三、功能特性对比
-
代码复用性
- 云函数 ➔ 通过模块化实现
const common = require('./common.js')
- 云对象 ➔ 天然支持继承/混入
class BaseObject { ... }
module.exports = class User extends BaseObject {...}
-
调试支持
- 云函数 ➔ 需要模拟event参数
- 云对象 ➔ 支持方法级断点调试
-
文档生成
- 云函数 ➔ 手动维护接口文档
- 云对象 ➔ 自动生成API文档(基于JSDoc)
-
性能表现
- 云函数 ➔ 单个函数独立冷启动
- 云对象 ➔ 对象级缓存(方法调用共享上下文)
四、生命周期对比
云函数生命周期:
客户端调用 ➔ 创建实例 ➔ 执行main函数 ➔ 销毁实例云对象生命周期:
客户端调用 ➔ 创建对象实例 ➔ 执行中间件 ➔ 执行目标方法 ➔ 保持常驻(可复用)
五、最佳实践对比
场景 | 推荐方案 | 示例 |
---|---|---|
简单原子操作 | 云函数 | 发送短信验证码 |
复杂业务逻辑 | 云对象 | 订单创建(涉及多表操作) |
高频调用接口 | 云对象(常驻内存) | 实时聊天消息处理 |
需要严格权限控制 | 云对象(中间件统一处理) | 支付操作 |
第三方服务对接 | 云函数 | 微信支付回调处理 |
六、代码结构对比
云函数典型结构
// cloudfunctions/user-function/index.js
exports.main = async (event, context) => {const { action, data } = eventswitch(action) {case 'addUser':return addUser(data)case 'deleteUser':return deleteUser(data)default:throw new Error('Invalid action')}
}function addUser(userData) { /* ... */ }
function deleteUser(userId) { /* ... */ }
云对象典型结构
// cloudobjects/user-object/index.js
module.exports = {// 前置中间件_before() {this.verifyToken() // 统一鉴权},/*** 添加用户* @param {Object} userData 用户数据*/async addUser(userData) {// 业务逻辑},/*** 删除用户* @param {string} userId 用户ID*/async deleteUser(userId) {// 业务逻辑},// 私有方法(不对外暴露)verifyToken() {// 鉴权逻辑}
}
七、迁移路径建议
传统云函数 ➔ 云对象演进路线:
1. 拆分功能模块 → 2. 封装业务对象 → 3. 添加中间件 → 4. 增加类型校验 → 5. 实现方法复用
关键结论:
- 新项目优先使用云对象(架构更清晰、维护成本低)
- 存量项目逐步迁移(混合使用两种方案)
- 性能敏感场景评估使用(云对象常驻内存 vs 云函数独立实例)
- 复杂业务必用云对象(继承/中间件/类型校验等特性优势明显)
通过对比可以看出,云对象在代码组织、开发效率和可维护性方面具有显著优势,而云函数在简单场景和特殊需求场景仍保有其适用价值。
四、云存储讲解
1. 云存储是什么?
云存储是uniCloud提供的文件存储服务,类似于“云端硬盘”,开发者可以快速上传、下载、管理文件(如图片、视频、文档等),无需自建文件服务器。
核心特点:
- 免运维:无需配置服务器或CDN,开箱即用。
- 权限控制:通过安全规则限制文件访问权限。
- 自动生成链接:上传后自动返回文件URL,可直接用于前端展示。
- 与数据库联动:文件ID可与云数据库关联,实现文件元数据管理。
以下是对 uni-app 云开发中 云存储(Cloud Storage) 的详细知识点讲解,采用结构化方式呈现:
一、核心功能概述
1. **文件全生命周期管理** - 上传 → 存储 → 处理 → 下载 → 删除
2. **多端统一API** - 支持Web/H5、小程序、App全平台
3. **CDN加速** - 自动全球分发,提升访问速度
4. **权限控制体系** - 支持「公有读/私有」两种访问模式
5. **文件处理能力** - 图片压缩、裁剪、水印- 视频截图、音频转码(需配置扩展)
二、核心操作API及示例
操作 | 方法示例 | 说明 |
---|---|---|
上传文件 | uniCloud.uploadFile() | 客户端或云函数上传文件到云存储 |
下载文件 | uniCloud.downloadFile() | 根据文件ID下载到本地临时路径 |
删除文件 | uniCloud.deleteFile() | 通过文件ID删除云端文件 |
获取文件列表 | uniCloud.getTempFileList() | 查询存储桶中的文件列表(需云函数调用) |
1. 文件上传(重点)
基础上传:
// 选择文件
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)
高级特性:
- 分片上传(大文件自动处理)
uniCloud.uploadFile({filePath: largeFile.path,cloudPath: 'bigfile.zip',uploadChunked: true // 启用分片 })
- 自定义metadata:
uploadFile({filePath: file.path,cloudPath: 'data.json',fileMeta: { // 自定义元数据category: 'config',version: '1.0'} })
2. 文件下载
// 公有读文件直接使用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. 文件删除
// 删除图片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'})}}}})}
配套云对象代码:
// 删除活动图片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. 文件管理
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. 权限配置方式
通过文件路径前缀控制:
cloud://env-id.7072-env-id-1303011235/ # 根目录
├─ public/ # 公有读目录
└─ private/ # 私有目录
动态权限管理(云函数中):
// 生成带时效的下载链接
const getSecureURL = async (fileID) => {return uniCloud.getTempFileURL({fileList: [fileID],expire: 3600 // 1小时有效})
}
四、文件处理能力
1. 图片处理(URL参数方式)
// 原图: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. 视频处理(需扩展)
// 获取视频封面
const videoCoverURL = videoFileID + '?vframe/jpg/offset/5'// 视频转码(HLS格式)
const hlsURL = videoFileID + '?transcode/hls'
五、安全防护策略
1. **上传防护** - 文件类型白名单(MIME类型检查)- 文件大小限制(单文件≤100MB)- 病毒扫描(需集成安全能力)2. **访问控制** - 私有文件临时URL时效性(默认1小时)- 防盗链设置(Referer白名单)3. **存储安全** - 自动多副本存储- 跨地域容灾备份4. **监控预警** - 异常流量告警- 敏感文件操作日志
六、最佳实践示例
这里给出一个用户头像上传的例子,帮助理解云存储的使用方法
1. 用户头像上传方案
1.1 选择并上传头像(前端)
<template><view class="container"><!-- 头像展示 --><image :src="avatarUrl" mode="aspectFill" @click="chooseAvatar" /><!-- 上传按钮 --><button @click="uploadAvatar">确认上传</button></view>
</template><script>
export default {data() {return {tempFilePath: '', // 临时文件路径avatarUrl: '', // 头像网络URLuserId: '' // 当前用户ID(可从uni-id获取)}},onLoad() {this.userId = uni.getStorageSync('uni_id') || ''; // 获取当前用户IDthis.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 可访问URLasync 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. 云函数(可选)
如果需要更复杂的逻辑(如图片压缩、敏感内容检测),可增加云函数处理:
// 云函数入口文件(cloudfunctions/avatar-processor/index.js)
exports.main = async (event, context) => {const { fileID, userId } = event;// 示例:调用图片压缩APIconst 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. 大文件分片上传优化
// 自定义分片策略
uniCloud.uploadFile({filePath: largeFile.path,cloudPath: 'bigfile.zip',uploadChunked: true,chunkSize: 2 * 1024 * 1024, // 2MB分片onChunkUpload: ({ progress, chunkIndex }) => {console.log(`分片${chunkIndex}上传完成`)}
})
七、调试与监控
1. 开发阶段调试
// 查看文件元数据
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. 开发阶段调试
// 查看文件元数据
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进行存储空间审计。