小程序開發(fā)實現(xiàn)access_token統(tǒng)一管理
TOKEN 定時刷新器
一、背景
對于使用過公眾平臺的API功能的開發(fā)者來說,access_token絕對不會陌生,它就像一個打開家門的鑰匙,只要拿著它,就能使用公眾平臺絕大部分的API功能。因此,對于開發(fā)者而言,access_token的使用方式就變得尤其的重要。在日常API接口的運營中,經常遇到各種的疑問:為什么我的access_token突然非法了?為什么剛剛拿到的access_token,用了10min就過期了?對于這些疑問,我們提供出access_token的設計方案,便于開發(fā)者對access_token使用方式上的理解。
對于access_token的獲取,可以參考公眾平臺的官方文檔:auth.getAccessToken、獲取Access token
二、access_token的內部設計
2.1 access_token的時效性
眾所周知,access_token是通過appid和appsecret來生成的。內部設計的步驟如下:
(1)開發(fā)者通過https請求方式: GET https://API.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,傳入appid及apppsecret的參數
(2)公眾平臺后臺會校驗appid和哈希(appsecret)是否與存儲匹配,若匹配,結合當前時間戳,生成新的access_token。
(3)生成新的access_token的同時,會對老的access_token的過期時間戳更新為當前時間戳。
(4)返回新的access_token給開發(fā)者。
這里以圖示的方式說明一下,新舊token交替過程:

從上圖需要注意的幾點:
(1)公眾平臺存儲層只會存儲新老兩個access_token,意味著假設開發(fā)者重復調用3次接口,則會導致最早的access_token立刻失效。
(2)雖然請求新的access_token后,老的access_token過期時間會更新為當前時間,但也不會立刻失效,原理請參考 【2.2 access_token 的逐漸失效性】
(3)出于信息安全考慮,公眾平臺并不會明文存儲appsecret,僅存儲appid以及appsecret的哈希值。因此開發(fā)者要妥善保管appsecret。當appsecret疑似泄露時,需要及時登錄mp.weixin.qq.com重置appsecret。
2.2 access_token 的逐漸失效性
從【access_token的時效性】了解到,當開發(fā)者請求獲取新的access_token時,老的access_token過期時間會被更新為當前時間,但此時不會立刻失效,因為公眾平臺會提供【5分鐘的新老access_token交替緩沖時間】,因此也稱為access_token
的逐漸失效性。
實現(xiàn)的原理是:
- 由于老的access_token過期時間戳已被刷新,所以在API接口請求期間,帶上的access_token解開后,過期時間戳會加上5分鐘,然后和當前設備時間進行比對,若超過當前設備時間,判斷為失效。
- 公眾平臺的設備會保持時鐘同步,但設備之間仍然可能會存在1-2分鐘的時間差異,所以【5分鐘】并非絕對的時間值。當開發(fā)者獲取到新的access_token后應該盡快切換到新的access_token。

從上圖需要注意的幾點:
(1)由于存在設備時間同步的差異,可能會導致開發(fā)者遇到拿著老的access_token請求API接口,部分請求成功,部分請求失敗的情況,建議開發(fā)者獲取到新的access_token后盡快使用。
(2)通過理解兩個圖示,對開發(fā)者來說,access_token是相當關鍵且不能亂調的接口,建議開發(fā)者統(tǒng)一管理access_token,以免造成多次請求導致access_token失效。
三、access_token的統(tǒng)一管理
將access_token的更新交給定時觸發(fā)器完成所有用到access_token的接口調用,不傳入access_token,交由后端從數據庫中讀取
下面以小程序云函數端統(tǒng)一管理access_token代碼為例展示
index.js 請求并更新access_token
如果在其他端,需要傳入APPID
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const timeutil = require('./timeutil');
// 需要修改的配置項
const APPSECRET = ''
const axios = require('axios');
const db = cloud.database();
// 定時刷新獲取配置信息
const CONFIG = 'cloud-token';
// 獲取TOKEN
const URL = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APPSECRET}'
function getAccessToken(APPID,APPSECRET){
let url = URL;
url = url.replace('{APPID}',APPID)
url = url.replace('{APPSECRET}',APPSECRET)
return new Promise(function(resolve,reject){
axios.get(url).then(function (response) {
console.log(response);
resolve(response)
})
.catch(function (error) {
console.log(error);
reject(error)
});
})
}
// 云函數入口函數
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
// 自動獲取當前應用APPID
var APPID = wxContext.APPID;
return new Promise(function(resolve,reject){
getAccessToken(APPID,APPSECRET).then(async res=>{
console.log(res)
let access_token = res.data.access_token;
let ans = await db.collection(CONFIG).doc('access_token').set({
data:{
value:access_token,
_updateTime:timeutil.TimeCode()
}
})
resolve(ans)
})
})
}
config.json 定時觸發(fā)器
每小時觸發(fā)一次
{
"triggers": [
{
"name": "myTrigger",
"type": "timer",
"config": "0 0 * * * * *"
}
]
}
timeutil.js 時間工具類
function TimeCode() {
var date = new Date();
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
//獲取日期
function _formatTime(time) {
var date = time.getFullYear() + '年' + time.getMonth() + '月' + time.getDate() + '日'
var ftime = time.getHours() + '時' + time.getMinutes() + '分' + time.getSeconds() + '秒'
return date + ftime;
}
function TimeCodeYmd(){
var date = new Date();
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
return [year, month, day].map(formatNumber).join('-');
}
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
module.exports={
TimeCode,
TimeCodeYmd
}
其他云函數中使用到access_token的地方,通過查詢數據庫進行獲取,二者通過數據庫進行邏輯耦合。
access_token 查詢使用
const TOKEN = 'cloud-token';
//獲取access_token
try {
let tres = await db.collection(TOKEN).doc('access_token').get();
access_token = tres.data.value;
console.log(access_token)
} catch (error) {
console.log('--無token記錄--')
return {
errCode:-1,
errMsg:'數據庫中無TOKEN信息'
}
}
參考文檔
【1】公眾平臺/小程序服務端API的access_token的內部設計 | 微信開放社區(qū) (qq.com)
【2】auth.getAccessToken | 微信開放文檔 (qq.com)
【3】微信小程序開發(fā)技巧總結(三)-- 云開發(fā)時效數據刷新和存儲 (access_token等) - Kindear - 博客園 (cnblogs.com)
到此這篇關于小程序開發(fā)實現(xiàn)access_token統(tǒng)一管理的文章就介紹到這了,更多相關小程序 access_token統(tǒng)一管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
點擊button獲取text內容并改變樣式的js實現(xiàn)
這篇文章主要介紹了點擊button獲取text內容并改變樣式的js實現(xiàn),經測試非常實用,需要的朋友可以參考下2014-09-09
JavaScript async&await方法中的異常處理方案
在 async/await 方法中,可以使用 try-catch 塊來處理異常,通過使用 try-catch,可以捕獲異步操作中拋出的異常,并在 catch 塊中進行適當的處理,本文給大家詳細介紹了async&await方法中異常如何處理,需要的朋友可以參考下2023-08-08
Ant Design Pro 下實現(xiàn)文件下載的實現(xiàn)代碼
這篇文章主要介紹了Ant Design Pro 下實現(xiàn)文件下載的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12
javascript tips提示框組件實現(xiàn)代碼
一個簡單的類似title的提示效果,但現(xiàn)實內容可以很豐富,以上js另存為tip.js,下面是使用的demo。2010-11-11

