uni-app云开发总结

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或聚合管道

如何选择?
  1. 选关系型:

    • 数据结构固定,需要强一致性(如银行交易)。

    • 复杂多表关联查询(如ERP系统)。

    • 事务密集型场景(如库存扣减)。

  2. 选非关系型:

    • 数据结构多变(如用户行为日志)。

    • 高并发读写(如社交平台动态)。

    • 水平扩展需求(如物联网海量设备数据)。


一句话总结最大区别

关系型数据库用"表格"锁死结构,保障严谨;非关系型数据库用"自由格式"换取弹性,拥抱变化。

根据业务需求在"严格规范"与"灵活扩展"之间权衡,是现代数据库选型的核心逻辑。

uni-app云数据库解析

在 uni-app 的云开发(uniCloud)中,数据库采用的是基于 JSON 文档的 NoSQL ( 非关系型 )数据库(类似 MongoDB)。以下是 uniCloud 数据库的核心类型概念解析:


1. 数据库类型特点

• 文档型数据库:数据以 JSON 文档 形式存储,无需预定义表结构(Schema),但可通过 Schema 规范数据格式。

• 集合(Collection):相当于关系型数据库中的"表",用于存储一组文档(如 users 集合存储用户数据)。

• 文档(Document):集合中的单条数据记录,格式为 JSON 对象(如一个用户的信息)。


2. 核心数据类型

uniCloud 数据库支持以下基础数据类型:

基本类型

类型 说明 示例
String 字符串 "Hello"
Number 数字(整型或浮点型) 1233.14
Boolean 布尔值 truefalse
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. 注意事项
  1. 类型严格性:查询时需匹配字段类型(如 Number 类型字段不能直接与字符串比较)。
  2. 地理位置索引:使用地理位置查询前需在 uniCloud 控制台创建 地理位置索引。
  3. 日期处理:数据库存储的是时间戳,需在客户端转换为 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方式 :支持动态权限(代码级控制)

    javascript 复制代码
    db.collection('articles').get({
      permission: { 
        read: "doc.status == 'published' || auth.uid == doc.author_id"
      }
    })
3. 查询性能优化
  • 传统方式 :需要手动创建索引

    javascript 复制代码
    db.createIndex({
      collectionName: 'articles',
      indexes: [{ name: 'category_index', fields: [{ category: 1 }] }]
    })
  • JQL方式:自动索引建议(控制台提示优化方案)

4. 数据类型处理
  • 传统方式 :严格类型校验(需手动处理Date等类型)

    javascript 复制代码
    db.collection('logs').add({
      timestamp: new Date().getTime() // 需显式转换
    })
  • JQL方式 :自动类型转换

    javascript 复制代码
    db.collection('logs').add({
      timestamp: new Date() // 自动转为时间戳
    })

五、使用场景建议

推荐使用 database() 的场景:
  1. 需要复杂聚合查询(如多阶段管道操作)
  2. 已有MongoDB开发经验的团队
  3. 需要直接操作数据库指令(如地理位置查询)
推荐使用 databaseForJQL() 的场景:
  1. 新项目启动(特别是前后端分离架构)
  2. 需要简化联表查询逻辑
  3. 希望在前端实现复杂业务逻辑
  4. 需要动态权限控制的场景

六、混合使用建议

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
}

七、注意事项

  1. JQL限制

    • 单次查询最多关联3张表
    • 客户端查询最大返回1000条数据
    • 复杂聚合仍需使用传统方式
  2. 迁移成本

    • 现有项目从传统方式迁移到JQL需重写查询逻辑
    • 两种方式的数据索引可以复用
  3. 安全规范

    • JQL客户端查询仍需配置安全规则
    • 敏感操作仍需通过云函数/云对象
  4. 性能监控

    • 控制台可分别查看两种方式的慢查询日志
    • JQL查询建议使用explain()分析执行计划
    javascript 复制代码
    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 等生命周期方法

二、技术特性对比

  1. 参数处理

    • 云函数 ➔ 需手动解析event参数

      js 复制代码
      exports.main = async (event) => {
         const { action, data } = event
      }
    • 云对象 ➔ 自动解析参数(方法直接接收)

    js 复制代码
    module.exports = {
      addUser(userData) { /* 直接使用userData */ }
    }
  2. 错误处理

    • 云函数 ➔ 需手动catch错误

      js 复制代码
      try { 
        await callFunction('func') 
      } catch(e) {...}
    • 云对象 ➔ 自动错误冒泡(客户端自动捕获)

      js 复制代码
      // 客户端自动接收标准化错误格式
  3. 中间件支持

    • 云函数 ➔ 自行实现中间件机制

      js 复制代码
      const auth = require('uni-id').checkToken(event.uniIdToken)
    • 云对象 ➔ 内置中间件系统

      js 复制代码
      module.exports = {
        _before() { // 统一鉴权逻辑 }
      }
  4. 类型校验

    • 云函数 ➔ 手动校验参数类型

      js 复制代码
      if(typeof event.name !== 'string') throw...
    • 云对象 ➔ 自动类型校验(基于JSDoc)

      js 复制代码
      /**
       * @param {string} userId
       * @param {number} newAge
       */
      updateAge(userId, newAge) {...}

三、功能特性对比

  1. 代码复用性

    • 云函数 ➔ 通过模块化实现

      const common = require('./common.js')

    • 云对象 ➔ 天然支持继承/混入

js 复制代码
class BaseObject { ... }
module.exports = class User extends BaseObject {...}
  1. 调试支持

    • 云函数 ➔ 需要模拟event参数
    • 云对象 ➔ 支持方法级断点调试
  2. 文档生成

    • 云函数 ➔ 手动维护接口文档
    • 云对象 ➔ 自动生成API文档(基于JSDoc)
  3. 性能表现

    • 云函数 ➔ 单个函数独立冷启动
    • 云对象 ➔ 对象级缓存(方法调用共享上下文)

四、生命周期对比

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. 实现方法复用

关键结论:

  1. 新项目优先使用云对象(架构更清晰、维护成本低)
  2. 存量项目逐步迁移(混合使用两种方案)
  3. 性能敏感场景评估使用(云对象常驻内存 vs 云函数独立实例)
  4. 复杂业务必用云对象(继承/中间件/类型校验等特性优势明显)

通过对比可以看出,云对象在代码组织、开发效率和可维护性方面具有显著优势,而云函数在简单场景和特殊需求场景仍保有其适用价值。

四、云存储讲解

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)

高级特性

  • 分片上传 (大文件自动处理)

    javascript 复制代码
    uniCloud.uploadFile({
      filePath: largeFile.path,
      cloudPath: 'bigfile.zip',
      uploadChunked: true // 启用分片
    })
  • 自定义metadata

    javascript 复制代码
    uploadFile({
      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次

关键结论:

  1. 路径规划原则

    • 按业务类型分目录(如 /user_upload//system_config/
    • 使用时间戳/UUID防止文件名冲突
  2. 性能优化重点

    • 前端压缩(减少传输量)
    • CDN缓存策略(合理设置Cache-Control)
    • 异步处理机制(大文件后台处理)
  3. 安全必做项

    • 设置上传文件类型白名单
    • 私有文件必须设置访问时效
    • 定期审计存储桶权限
  4. 成本控制技巧

    • 开启低频存储类型
    • 设置生命周期自动删除临时文件
    • 使用图片处理减少存储冗余

}.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次

关键结论:

  1. 路径规划原则

    • 按业务类型分目录(如 /user_upload//system_config/
    • 使用时间戳/UUID防止文件名冲突
  2. 性能优化重点

    • 前端压缩(减少传输量)
    • CDN缓存策略(合理设置Cache-Control)
    • 异步处理机制(大文件后台处理)
  3. 安全必做项

    • 设置上传文件类型白名单
    • 私有文件必须设置访问时效
    • 定期审计存储桶权限
  4. 成本控制技巧

    • 开启低频存储类型
    • 设置生命周期自动删除临时文件
    • 使用图片处理减少存储冗余

通过合理使用云存储能力,结合uni-app的多端特性,可以构建高效安全的文件管理系统。建议结合uni-admin进行可视化文件管理,并定期使用listFilesAPI进行存储空间审计。

相关推荐
七七小报2 小时前
uniapp-商城-38-shop 购物车 选好了 进行订单确认4 配送方式1
uni-app
七七小报4 小时前
uniapp-商城-39-shop 购物车 选好了 进行订单确认4 配送方式2 地址页面
uni-app
G_GreenHand4 小时前
uniapp 仿小红书轮播图效果
uni-app
性野喜悲6 小时前
uniapp返回上一页接口数据更新了,页面未更新
uni-app
冰镇生鲜8 小时前
小程序·安全·胶囊·容器组件
前端·vue.js·uni-app
halo14168 小时前
uni-app 小程序中的定位问题 以及 页面安全距离
小程序·uni-app
资深前端之路8 小时前
iphonex uniapp textarea标签兼容性处理过程梳理
uni-app
xx24061 天前
UniApp学习笔记
uni-app
七七小报1 天前
uniapp-商城-36-shop 购物车 选好了 进行订单确认2 支付方式颜色变化和颜色滤镜filter
uni-app