前言
陶瓷的许多接口都需要我们携带正确的 access_token
才能访问, 这个东西相当于现实中的身份证, 下面简称票据. 票据是通过我们用app_id和app_secret获取的. 而且每两个小时过期, 每日获取上限是2000次.
原理
我们在访问某些接口前, 先去获取票据, 携带上再访问接口. 但因为有每日2000次的限制, 所以我们获取后应该缓存到本地, 我是缓存到一个json文件中的. 又因为2个小时的过期时间, 所以我们应该在缓存票据的时候设置一个过期时间. 如果当前时间大于过期时间, 就代表票据失效了, 需要我们重新去获取票据.
其实还有另一种实现, 就是使用一个定时器, 每1.5小时自动获取票据并缓存, 不过这个要下载一个npm包.
实现
我使用了第一种实现.(www.hedaoshe.com)
//在调用某些接口前应该先调用这个方法,
//flag参数是用来区分不同陶瓷的标志
//二次开发的目的在我看来是为了一个后台运营多个陶瓷
async getAccessToken(flag){
//从缓存文件中获取存储了所有access_token的对象
let allAccessTokenInfoObj = FileUtil.getJsonObjFromFile(weixinConfig.common.accessTokenFilePath)
//判断access_token的合法性
if(!this._isValidAccessToken(allAccessTokenInfoObj,flag)){
//如果不合法就去微信后台重新获取access_token,并缓存
allAccessTokenInfoObj = await this._updateAccessToken(allAccessTokenInfoObj,flag)
}
//返回我们需要的access_token
return allAccessTokenInfoObj[flag].accessToken
}
/**
* @Date: 2020-10-22 15:21:00
* @author: qiud
* @description: 验证票据是否有效
* 1. 票据不存在
* 2. 票据过期
* @param {object} allAccessTokenInfoObj 所有票据的对象
* @param {string} flag 陶瓷标识, 用来判断获取哪个公众的票据
* @return {boolean} 是否有效
*/
_isValidAccessToken(allAccessTokenInfoObj,flag){
//文件中没有accessToken信息,或者不完整
if(!allAccessTokenInfoObj[flag] || Object.keys(allAccessTokenInfoObj[flag]).length < 2){
return false
}
//有accessToken信息, 但已经过期
const now = new Date().getTime()
if(allAccessTokenInfoObj[flag].expireTime<=now){
return false
}
return true
}
/**
* @Date: 2020-10-22 15:20:02
* @author: qiud
* @description: 更新票据
* @param {object} allAccessTokenInfoObj 存储所有票据的对象
* @param {string} flag 陶瓷标识, 用来判断获取哪个公众的票据
* @return {Promise<object>} 所有票据对象, 包含过期时间
*/
async _updateAccessToken(allAccessTokenInfoObj,flag){
//根据flag去数据库找到对应appId和secret
const platformInfo = await WeiXinPlatformModel.findOne({
where:{
flag,
}
})
if(!platformInfo){
throw new NotFound(`标识符 ${flag} 没有对应的陶瓷!`)
}
//组装请求票据的url
const url = StrUtil.replace(weixinConfig.api.getAccessTokenGet,[platformInfo.appId,platformInfo.appSecret])
//请求票据
const res = await axios({
url,
method:'GET',
})
if(res.data.errcode){
throw new GetAccessTokenException(res.data.errmsg)
}
//设置过期时间
const expireTime = TimeUtil.createExpireTimestamp(weixinConfig.common.expireTime)
//把新票据和过期时间整合到所有票据对象上面
allAccessTokenInfoObj[flag] = {
accessToken:res.data.access_token,
expireTime,
}
//保存到缓存文件中
FileUtil.saveJsonObjToFile(weixinConfig.common.accessTokenFilePath,allAccessTokenInfoObj)
//返回所有票据对象
return allAccessTokenInfoObj
}
总结
整个实现是非常清晰的, 我们来复盘下.
- 去缓存文件找到对应的票据,
- 验证这个票据的合法性. 如果合法则直接获取该票据. 不合法则先去微信后台请求票据, 再缓存起来, 最后返回票据对象.
- 拿到我们需要的票据.