第三篇中,封装了网络请求,咋看一下貌似还可以,实际运用中发生很多问题。
一,代码不够优雅。
二,之前的版本是每次有请求后去判断token是否过期,但是取的token还是之前数据库里的token,如果长时间小程序没人访问的话,这个数据库保存的token其实已经过期了。
那么只能再修改一下代码,思路就是,每一次的网络请求,都要去判断一下token是否过期,如果已经过期,则从后端重新获取token,然后更新数据库,并且返回最新的token。
好了,让我们开始修改代码吧。
先新建一个文件夹,cloud,两个云函数
然后在配置文件中加上以下代码
"cloudfunctionRoot": "cloud/",
那么,cloud文件夹的边上,就会出现一朵云。
然后新建getdbtoken,和refushtoken两个云函数
getdbtoken函数功能主要是获取当前云数据库里保存的token。
云函数需要接受一个参数databasetokenID,然后通过id查找数据库对应的token。
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const {
databasetokenID
} = event
return new Promise((resolve, reject) => {
cloud.database().collection('localtoken').doc(databasetokenID).get()
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err)
})
})
}
http.js就是封装了网络请求的,思路就是,先去getdbtoken获取token,然后根据当前时间和过期时间判断,是否已经快过期了,如果快过期,则执行refushtoken云函数返回使用返回的token发送网络请求,如果没有过期,则使用原来数据库中保存的token发送网络请求,代码如下:
import config from '../config'
const {
pubUrl,
apikey,
userID,
databasetokenID
} = config
//这是我要请求的数据接口的公共部分
let requestTimes = 0
const http = (options) => {
requestTimes++
wx.showLoading({
title: '加载中',
mask: true
})
return new Promise((resolve, reject) => {
wx.cloud.callFunction({
name: 'getdbtoken',
data: {
databasetokenID
}
})
.then(dbtoken => {
let access_token = dbtoken.result.access_token
const expiresIn = Number.parseInt(dbtoken.result.expiresIn)
const createtime = Number.parseInt(dbtoken.result.createtime)
const currtime = Math.floor(Date.now() / 1000)
console.log(createtime)
console.log(expiresIn + createtime)
console.log(currtime + expiresIn / 2)
//expiresIn + createtime < currtime + expiresIn / 2
if (expiresIn + createtime < currtime + expiresIn / 2) {
console.log('刷新token咯')
wx.cloud.callFunction({
name: 'refushtoken',
data: {
pubUrl,
apikey,
userID,
databasetokenID
}
}).then(res => {
console.log('云函数来的token', res.result)
resolve(httprequest(options,res.result) )
})
} else {
resolve(httprequest(options,access_token))
}
})
.catch((err) => {
console.log('错误', err)
})
})
}
function httprequest(options,access_token) {
return new Promise((resolve, reject) => {
console.log('request里的token',access_token)
wx.request({
url: pubUrl + options.url,
method: options.method || 'get',
data: options.data || {},
header: {
'authorization': access_token
},
success(res) {
if (res.statusCode === 200) {
//如果状态正确,则返回数据
resolve(res.data)
}
else {
reject(res)
}
},
fail(error) {
reject(error)
},
complete() {
requestTimes--
if (requestTimes == 0) {
wx.hideLoading({
success: (res) => {}
})
}
}
})
})
}
module.exports = http
核心部分就是refushtoken这个云函数,云函数也是异步返回数据的,如果想阻塞当前进程,直到有返回值再进行下一步,同样的需要进行promise包装,代码如下:
// 云函数入口文件
const cloud = require('wx-server-sdk')
const request = require('request-promise')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const {
pubUrl,
apikey,
userID,
databasetokenID
} = event
const url = `${pubUrl}/common/token?id=${userID}&key=${apikey}`
return new Promise((resolve, reject) => {
request({
url,
json: true
}).then(res => {
const {
createtime,
expiresIn,
access_token
} = res.data
cloud.database().collection('localtoken').doc(databasetokenID)
.update({
data: {
access_token,
createtime,
expiresIn
}
}).then(() => {
resolve(access_token)
})
.catch(err=>{
reject(err)
})
})
})
}
至此总算完成代码