所谓serverless就是无后台开发。通俗地说就是踢开后端闹革命。只需要一个前端就可以操作数据库小程序云开发
就是这个概念的尝鲜者。云开发也是小程序近年最大的改变之一。
云开发文档 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html
云函数,数据库和文件储存构成了云开发的核心三大件。
腾讯是这么说的:一个前端凭借云开发,就能够搞定一个两亿级别的应用。(商业案例:腾讯云相册)
在微信开发者工具中点击"云开发",开通后可以进入到云开发的控制台。
微信给你免费送了一些有用的功能。那就是你的后台了。
运维中心
凭借运维中心,运维人员也可以踢开了。
听到这些广告词,是不是心动了呢。
数据库
数据库也是一个黑盒,但是表现很像mongodb。本质上应该是一个文档型数据库。
云开发提供了一个 JSON 数据库,顾名思义,数据库中的每条记录都是一个 JSON 格式的对象。一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-server-api/database/
怎么用呢?
新建一个基于云开发的小程序项目。
发现目录结构变了,原来的小程序结构放到了miniprogram
文件夹:
增加了一个cloudfunctions文件夹。
你可以在页面中const db = wx.cloud.database()
拿到数据库。
调用时你可以
代码语言:javascript复制db.add({
// balabala
})
add可以替换为get等等。
代码语言:javascript复制 getbooks(){
// 小程序端直接读库
db.collection('books').get({
success:(res)=>{
console.log(res)
this.setData({
books:res.data
})
}
});
},
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-client-api/database/
前端不再去写什么http请求了。以下实现一个才子书列表的基本管理。
代码语言:javascript复制<scroll-view>
<view class="title">才子书</view>
<input bindinput="input" wx:value="{{addContent}}" class="add-book" />
<button bindtap="addbook" type="primary">添加</button>
<view wx:for="{{books}}" >
<view>
<text>{{item.name}}-{{item.author}}-{{item._id}} </text>
<text class="delete" data-id="{{item._id}}" bindtap="delete">删除</text>
</view>
</view>
</scroll-view>
代码语言:javascript复制const db = wx.cloud.database()
Page({
data: {
books: [],
addContent: ''
},
onLoad() {
this.getbooks();
},
delete(e) {
const { id } = e.currentTarget.dataset;
db.collection('books').doc(id).remove({
success: (res) => {
console.log(res)
this.getbooks();
}
})
},
getbooks() {
// 小程序端直接读库
db.collection('books').get({
success: (res) => {
// console.log(res)
this.setData({
books: res.data
})
}
});
},
input(e) {
this.setData({
addContent: e.detail.value
})
},
addbook() {
// 加库
db.collection('books').add({
data: {
name: this.data.addContent,
author: 'djtao'
},
success: (res) => {
this.getbooks();
this.setData({
addContent: ''
})
}
});
}
})
注意你的才子书数据库,应做如下设置
实际上小程序最多只允许用户操作自己创建的数据。允许删除的列表建议放另外一个collection。
云函数
云函数是一系列nodejs的npm项目。可以使用npm安装自己需要的依赖。帮助实现一些额外功能。能力包括:
- 服务器
- 储存
- 工具插件引入
基本使用
接下来体验一下云函数的"魅力",新建一个me页面。
然后在开发者工具编辑器中"新建nodejs云函数",命名为login。
新建之后有以下配置,其实就是一个npm项目:
代码语言:javascript复制// 云函数模板
// 部署:在 cloud-functions/login 文件夹右击选择 “上传并部署”
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init()
/**
* 这个示例将经自动鉴权过的小程序用户 openid 返回给小程序端
*
* event 参数包含小程序端调用传入的 data
* 暴露云函数的入口
*/
exports.main = (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,
}
}
exports.main是暴露出来的云函数入口,我们稍微改一下:
代码语言:javascript复制exports.main = async (event, context) => {
const {a,b}=event;
return await {
sum:a b
}
}
写完之后就可以部署了。
怎么使用呢?通过wx.cloud.callFunction
调用
Page({
data: {},
onLoad() {
wx.cloud.callFunction({ // 云函数名称
name: 'login',
// 传给云函数的参数 data:
data: { a: 1, b: 2, },
success(res) {
console.log(res.result.sum) // 3
},
fail(err) {
console.error(err)
}
});
}
})
好了,现在进入到me页面,打印出来的就是1 2的结果3。
实际上云函数做的东西多的多。
完善云函数login
小程序最重要的就是登录。现在就把登录功能给做了。
登录最紧要就是获取openid。
获取openid
代码语言:javascript复制const cloud = require('wx-server-sdk')
cloud.init()
exports.main = (event, context) => {
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
}
}
打开云开发控制台,就可以看到登录的调用情况。
代码语言:javascript复制Page({
data: {
userInfo: {}
},
onLoad(){
// 获取登录态
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
this.setData({
avatarUrl: res.userInfo.avatarUrl,
userInfo: res.userInfo
})
}
})
}
}
})
},
// 点击按钮登录
onGetUserInfo(e) {
// console.log('coGetUserInfo', e)
if (e.detail.userInfo) {
this.setData({
avatarUrl: e.detail.userInfo.avatarUrl,
userInfo: e.detail.userInfo
})
}
}
})
持久化储存openid
代码语言:javascript复制wx.setStorageSync('userInfo',userInfo)
所以流程就是:获取openid,然后,获取用户信息。
代码语言:javascript复制 onLogin(){
let _this=this;
// 调用云函数
wx.cloud.callFunction({
name: 'login',
data: {},
success: res => {
console.log('[云函数] [login] user openid: ', res.result.openid)
app.globalData.openid = res.result.openid;
wx.getUserInfo({
success: res => {
_this.setData({
avatarUrl: res.userInfo.avatarUrl,
userInfo: res.userInfo
})
}
})
},
fail: err => {
console.error('[云函数] [login] 调用失败', err)
wx.showToast({
title: '获取用户信息失败',
icon: 'none',
image: '',
duration: 1500,
mask: false,
success: (result) => {
},
fail: () => {},
complete: () => {}
});
}
})
},
案例:扫码添加图书信息。
需求:
- 用户扫码(isbn)
- 根据isbn去豆瓣找信息
- 爬取图书信息,存储到云数据库。
我们的测试条形码是:
调起扫码
先让微信客户端调起扫码功能。
代码语言:javascript复制 callLogin(){
wx.scanCode({
success (res) {
console.log(res)
}
})
}
点击扫码调用这个函数,其中result就是这个结果。
获取豆瓣读书信息
下一步就是根据扫码结果进行查询。
豆瓣的公开接口是:https://book.douban.com/subject_search?search_text=
遗憾的是,你在postman看不到任何跟搜索结果有关的信息。(被加密了)
这时候可以用一个叫做doubanbook
的npm包来解析这串解密数据。
新增一个getBookInfo
云函数,
给他装上依赖:
代码语言:javascript复制npm i axios doubanbook -s
代码语言:javascript复制// 云函数入口文件
const cloud = require('wx-server-sdk');
const doubanbook=require('doubanbook');
const axios=require('axios');
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const {isbn}=event;
const url=`https://book.douban.com/subject_search?search_text=${isbn}`;
let res=await axios.get(url);
let reg=/window.__DATA__ = "(.*)"/;
let searchData=null;
if(reg.test(res.data)){
searchData=doubanbook(RegExp.$1)[0];
}
return {
searchData
}
}
小程序端调用:
代码语言:javascript复制 addBook(isbn){
let res=wx.cloud.callFunction({
name:'getBookInfo',
data:{
isbn
},
success(data){
console.log(data)
}
})
},
在本地调试一下,就拿到结果了。
好了,把展示界面简单写一写:扫码的结果就出来了。
所以,云函数本质上是一个小小的nodejs服务。所以nodejs是基础。
继续爬?
入库前想一想,我们想要的数据是什么?
当前拿到的数据还是非常有限的。有了链接,那意味着可以继续爬。详情链接是没有加密的。
用cheerio来爬吧!
代码语言:javascript复制 // 详情页数据
const detailData=await axios.get(searchData.url);
const $=cheerio.load(detailData.data);
// 以jq形式调用数据
const summary=$('#link-report .intro').text();
const info=$('#info').text().split('n').map(v=>v.trim()).filter(v=>v);
const auhtor=info[1];
return {
searchData,
creatTime:new Date().getTime(),
detailData,
auhtor,
summary,
info,
}
实际上你把爬虫写在这里是比较累人的。很有可能超时。
入库
拿到数据就考虑入库了。这里只考虑入库书名和作者。
入库的时候增加判断openid:
代码语言:javascript复制 addBooktoList() {
// 加库
// console.log(app.globalData.openid)
db.collection('books').add({
data: {
name: this.data.bookInfo.title,
author: 'djtao',
openid:wx.getStorageSync('userInfo').openid
},
success: (res) => {
console.log(res)
wx.showToast({
title: '成功',
icon: 'none',
image: '',
duration: 1500,
mask: false,
success: (result) => {
},
fail: () => {},
complete: () => {}
});
}
});
}