使用场景:
所有的业务逻辑都仅仅需要在小程序端完成,无需过于复杂的管理逻辑
开发者可以使用云开发开发微信小程序、小游戏,无需搭建服务器,即可使用云端能力。云开发为开发者提供完整的原生云端支持和微信服务支持,弱化后端和运维概念,无需搭建服务器,使用平台提供的 API 进行核心业务开发,即可实现快速上线和迭代,同时这一能力,同开发者已经使用的云服务相互兼容,并不互斥。
云开发提供了几大基础能力支持:
能力 | 作用 | 说明 |
---|---|---|
云函数 | 无需自建服务器 | 在云端运行的代码,微信私有协议天然鉴权,开发者只需编写自身业务逻辑代码 |
数据库 | 无需自建数据库 | 一个既可在小程序前端操作,也能在云函数中读写的 JSON 数据库 |
存储 | 无需自建存储和 CDN | 在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理 |
云调用 | 原生微信服务集成 | 基于云函数免鉴权使用小程序开放接口的能力,包括服务端调用、获取开放数据等能力 |
云开发控制台
云开发提供了一个控制台用于可视化管理云资源。控制台包含以下几大模块。
- 概览:查看云资源的总体使用情况
- 用户管理:查看小程序的用户访问记录
- 数据库:管理数据库集合、记录、权限设置、索引设置,可以添加,导入和导出数据
- 存储管理:管理云文件、权限设置,上传的图片,视频等文件可以在存储里看到
- 云函数:管理云函数、查看调用日志、监控记录,
- 统计分析:查看云资源详细使用统计
初始化(小程序端和云函数端)
小程序端
在小程序端开始使用云能力前,需先调用 wx.cloud.init
方法完成云能力初始化
App({
onLaunch: function () {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力')
} else {
wx.cloud.init({
// env 参数说明:
// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
env: 'my-env-id',
// 是否在将用户访问记录到用户管理中,在控制台中可见
traceUser: true,
})
}
this.globalData = {}
}
})
env还可以传入对象,指定各个服务的默认环境,可选字段可以去 文档里面查找
云函数端
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
注意:env
设置只会决定本次云函数 API 调用的云环境,并不会决定接下来其他被调云函数中的 API 调用的环境,在其他被调云函数中需要通过 init
方法重新设置环境。(每一个云函数都要调用 init
)
建议:在设置 env
时指定 cloud.DYNAMIC_CURRENT_ENV
常量 (需 SDK v1.1.0
或以上) ,这样云函数内发起数据库请求、存储请求或调用其他云函数的时候,默认请求的云环境就是云函数当前所在的环境:
云函数上手
创建cloudfunctions文件夹,里面存放所有云函数,然后在项目根目录里创建 project.config.json
文件,新增 cloudfunctionRoot
字段,指定本地已存在的目录作为云函数的本地根目录,完成指定后,图标会变成“云目录图标”
{
"cloudfunctionRoot": "./`cloudfunctions`/"
}
接着,在cloudfunctions目录上右键,选择创建一个新的Node.js云函数,命名为login,创建成功后会看到login文件夹里面有以下三个文件
- config.json:配置文件
- index.js:入口文件
- package.json
登录函数
小程序有很多需求都需要拿到openid和APPID,我们都是通过与后台对接才能拿到,而在云开发中不需要这么复杂
云开发的云函数的独特优势在于与微信登录鉴权的无缝整合。当小程序端调用云函数时,云函数的传入参数中会被注入小程序端用户的 openid,开发者无需校验 openid 的正确性,因为微信已经完成了这部分鉴权,开发者可以直接使用该 openid。与 openid 一起同时注入云函数的还有小程序的 appid。从小程序端调用云函数时,开发者可以在云函数内使用
wx-server-sdk
提供的getWXContext
方法获取到每次调用的上下文(appid
、openid
等),无需维护复杂的鉴权机制,即可获取天然可信任的用户登录态(openid
)。
下面就是具体的实现方法:
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
/**
* 这个示例将经自动鉴权过的小程序用户 openid 返回给小程序端
* event 参数包含小程序端调用传入的 data
*/
exports.main = async (event, context) => {
console.log(event)
console.log(context)
// 可执行其他自定义逻辑
// console.log 的内容可以在云开发云函数调用日志查看
// 获取 WX Context (微信调用上下文),包括 OPENID、APPID、及 UNIONID(需满足 UNIONID 获取条件)等信息
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
env: wxContext.ENV,
}
}
云函数的传入参数有两个,一个是event
对象,一个是context
对象。
event
指的是触发云函数的事件,当小程序端调用云函数时,event
就是小程序端调用云函数时传入的参数,外加后端自动注入的小程序用户的 openid 和小程序的 appid。
context
对象包含了此处调用的调用信息和运行状态,可以用它来了解服务运行的情况。
在模板中也默认require
了wx-server-sdk
,这是一个帮助我们在云函数中操作数据库、存储以及调用其他云函数的微信提供的库
UnionID云函数获取途径
如果满足下面两种条件,也可以直接在云函数里拿到用户的unionid
- 小程序端调用云函数时,如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号,可在云函数中通过 cloud.getWXContext 获取 UnionID。
- 小程序端调用云函数时,如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用,也可在云函数中通过 cloud.getWXContext 获取 UnionID。
在小程序端调用这个云函数前,我们需要先将这个云函数部署到云端才可以。在云函数目录上右键,可以将云函数整体打包上传并部署到线上环境中。
上传成功后login文件夹的icon会变成绿色的,证明我们已经部署成功了
我们可以到云开发控制台>云函数的云函数列表里面看到我们部署的云函数
部署完成后,我们可以在小程序中调用该云函数:
小程序端调用云函数
wx.cloud.callFunction({
name: 'login', // 云函数的文件夹名
data: {},
success: res => {
console.log('[云函数] [login] user openid: ', res.result.openid)
app.globalData.openid = res.result.openid
},
fail: err => {
console.error('[云函数] [login] 调用失败', err)
}
})
可以到Netword > cloud里面看到请求
数据库
打开云开发控制台的数据库标签,通过 "添加集合" 入口创建一个集合。假设我们要创建一个待办事项小程序,我们创建一个名为 counters
的集合。创建成功后,可以看到 counters
集合管理界面,界面中我们可以添加记录、查找记录、管理索引、管理权限和导入导出数据
增删改查(SDK)
了解了数据库之后我们开始学习如何在小程序端使用API进行增删改查操作,在那之前我们需要先需要先获取数据库的引用
const db = wx.cloud.database()
如需获取其他环境的数据库引用,可以在调用时传入一个对象参数,在其中通过 env
字段指定要使用的环境。此时方法会返回一个对测试环境数据库的引用。
示例:假设有一个环境名为 test
,用做测试环境,那么可以如下获取测试环境数据库:
const testDB = wx.cloud.database({
env: 'test'
})
如果要操作counters
集合需先获取它的引用。在获取了数据库的引用后,就可以通过数据库引用上的 collection
方法获取一个集合的引用了
const counters = db.collection('counters')
增
可以通过在集合对象上调用 add
方法往集合中插入一条记录
onAdd: function () {
const db = wx.cloud.database()
db.collection('counters').add({
data: {
count: 1
},
success: res => {
// 在返回结果中会包含新创建的记录的 _id
this.setData({
counterId: res._id,
count: 1
})
wx.showToast({
title: '新增记录成功',
})
console.log('[数据库] [新增记录] 成功,记录 _id: ', res._id)
},
fail: err => {
wx.showToast({
icon: 'none',
title: '新增记录失败'
})
console.error('[数据库] [新增记录] 失败:', err)
}
})
}
在创建成功之后,我们可以在控制台中查看到刚新增的数据。
Promise 风格也是支持的,只要传入对象中没有 success
, fail
或 complete
,那么 add
方法就会返回一个 Promise:
onAdd: function () {
const db = wx.cloud.database()
db.collection('counters').add({
data: {
count: 1
}
})
.then(res => {
wx.showToast({
title: '新增记录成功',
})
})
}
查
在记录和集合上都有提供 get
方法用于获取单个记录或集合中多个记录的数据。
获取一个记录的数据
假设我们已有一个 ID 为 counters-identifiant
的在集合 counters 上的记录,那么我们可以通过调用 doc
方法获取这条记录:
db.collection('counters').doc('counters-identifiant').get({
success: function(res) {
// res.data 包含该记录的数据
console.log(res)
}
})
获取多个记录的数据
我们也可以一次性获取多条记录。通过调用集合上的 where
方法可以指定查询条件,再调用 get
方法即可只返回满足指定查询条件的记录
db.collection('counters').where({
_openid: 'user-open-id',
done: false
})
.get({
success: function(res) {
// res.data 是包含以上定义的两条记录的数组
console.log(res.data)
}
})
获取一个集合的数据
在小程序中我们需要尽量避免一次性获取过量的数据,只应获取必要的数据。为了防止误操作以及保护小程序体验,小程序端在获取集合数据时服务器一次默认并且最多返回 20 条记录,云函数端这个数字则是 100。开发者可以通过 limit
方法指定需要获取的记录数量,但小程序端不能超过 20 条,云函数端不能超过 100 条
db.collection('todos').get({
success: function(res) {
// res.data 是一个包含集合中有权限访问的所有记录的数据,不超过 20 条
console.log(res.data)
}
})
改
更新数据主要有两个方法:
API | 说明 |
---|---|
update | 局部更新一个或多个记录 |
set | 替换更新一个记录 |
局部更新
onCounterInc: function() {
const db = wx.cloud.database()
const newCount = this.data.count + 1
db.collection('counters').doc(this.data.counterId).update({
data: {
count: newCount
},
success: res => {
this.setData({
count: newCount
})
},
fail: err => {
icon: 'none',
console.error('[数据库] [更新记录] 失败:', err)
}
})
}
替换更新
如果需要替换更新一条记录,可以在记录上使用 set
方法,替换更新意味着用传入的对象替换指定的记录:
onCounterInc: function() {
const db = wx.cloud.database()
const newCount = this.data.count + 1
db.collection('counters').doc(this.data.counterId).set({
data: {
description: "learn cloud database",
count: newCount,
style: {
color: "skyblue"
},
item: 'apple',
done: true
},
success: res => {
},
fail: err => {
icon: 'none',
console.error('[数据库] [更新记录] 失败:', err)
}
})
}
删
删除一条记录
对记录使用 remove
方法可以删除该条记录,比如:
onRemove: function() {
if (this.data.counterId) {
const db = wx.cloud.database()
db.collection('counters').doc(this.data.counterId).remove({
success: res => {
wx.showToast({
title: '删除成功',
})
this.setData({
counterId: '',
count: null,
})
},
fail: err => {
wx.showToast({
icon: 'none',
title: '删除失败',
})
console.error('[数据库] [删除记录] 失败:', err)
}
})
} else {
wx.showToast({
title: '无记录可删,请先创建一个记录',
})
}
},
删除多条记录
如果需要更新多个数据,需在 Server 端进行操作(云函数)。可通过 where
语句选取多条记录执行删除,只有有权限删除的记录会被删除。比如删除所有done = true的
// 使用了 async await 语法
const cloud = require('wx-server-sdk')
const db = cloud.database()
exports.main = async (event, context) => {
try {
return await db.collection('counters').where({
done: true
}).remove()
} catch(e) {
console.error(e)
}
}
更多数据库的操作可以去官方文档里面学习
存储
云存储提供高可用、高稳定、强安全的云端存储服务,支持任意数量和形式的非结构化数据存储,如视频和图片,并在控制台进行可视化管理。云存储包含以下功能:
- 存储管理:支持文件夹,方便文件归类。支持文件的上传、删除、移动、下载、搜索等,并可以查看文件的详情信息
- 权限设置:可以灵活设置哪些用户是否可以读写该文件夹中的文件,以保证业务的数据安全
- 上传管理:在这里可以查看文件上传历史、进度及状态
- 文件搜索:支持文件前缀名称及子目录文件的搜索
- 组件支持:支持在
image
、audio
等组件中传入云文件 ID
上传文件
在小程序端可调用 wx.cloud.uploadFile
方法进行上传:
wx.cloud.uploadFile({
cloudPath: 'example.png', // 上传至云端的路径
filePath: '', // 小程序临时文件路径
success: res => {
// 返回文件 ID
console.log(res.fileID)
},
fail: console.error
})
上传成功后会获得文件唯一标识符,即文件 ID,后续操作都基于文件 ID 而不是 URL。
下载文件
可以根据文件 ID 下载文件,用户仅可下载其有访问权限的文件:
wx.cloud.downloadFile({
fileID: '', // 文件 ID
success: res => {
// 返回临时文件路径
console.log(res.tempFilePath)
},
fail: console.error
})
删除文件
可以通过 wx.cloud.deleteFile
删除文件:
wx.cloud.deleteFile({
fileList: ['a7xzcb'],
success: res => {
// handle success
console.log(res.fileList)
},
fail: console.error
})
更详细的 API 可参考小程序端及后端存储 API 文件。
组件支持
支持在 image
、audio
等组件中传入云文件 ID
换取临时链接
可以根据文件 ID 换取临时文件网络链接,文件链接有有效期为两个小时:
wx.cloud.getTempFileURL({
fileList: ['cloud://xxx.png'],
success: res => {
// fileList 是一个有如下结构的对象数组
// [{
// fileID: 'cloud://xxx.png', // 文件 ID
// tempFileURL: '', // 临时文件网络链接
// maxAge: 120 * 60 * 1000, // 有效期
// }]
console.log(res.fileList)
},
fail: console.error
})