专栏目录请点击
js-sdk
的时候,需要使用临时票据jsapi_ticket
,他的有效期是7200秒,且调用的次数非常有限,所以我们尽量把它缓存下来jsapi_ticket
的时候,我们还是需要access_token
,获取jsapi_ticket
的接口为https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
access_token
,我们把它写到WeChat
这个类下,并模仿access_token
获取的步骤来写const prefix = "https://api.weixin.qq.com/cgi-bin/"
module.exports = {
ticket:`${prefix}ticket/getticket?type=jsapi`
}
我们模仿获取access_token
的方法,在WeChat类中写以下几个方法
// 获取jsapi_ticket的方法
getTicket() {
// 因为需要异步获取,这里返回promise
return new Promise(async(resolve,reject) => {
const data = await this.fetchAccessToken()
console.log("data",data);
const url = `${api.ticket}&access_token=${data.access_token}`
console.log(url)
rp({ method: "GET", url, json: true }).then(res => {
// 格式化
const {ticket,expires_in} = res
console.log(res)
resolve({
ticket,
ticket_expires_in:Date.now() + (expires_in -300) * 1000
})
}).catch(err => {
reject(err)
})
})
}
// 保存jsapi_ticket的方法
saveTicket(ticket) {
const ticket_str = JSON.stringify(ticket) // 转化为字符串,不然保存的就是[object object]
// 保存到本地accress_token.txt文件中,因为writeFile是一个异步方法,所以我们返回一个promise
return new Promise((resolve, reject) => {
writeFile("./ticket.txt", ticket_str, err => {
if (!err) {
resolve()
} else {
reject(err)
}
})
})
}
// 读取access_token的方法
readTicket() {
return new Promise((resolve, reject) => {
readFile("./ticket.txt", (err, data) => {
if (!err) {
// 转化为js对象
data = data.toString()
data = JSON.parse(data)
resolve(data)
} else {
reject(err)
}
})
})
}
// 验证token是否有效的方法
isValidTicket(data) {
// data 为读取文件
if (!data || !data.ticket || !data.ticket_expires_in) return false
return data.ticket_expires_in > Date.now()
}
fetchTicket() {
// 获取一次后,如果有直接返回
if (this.ticket && this.ticket_expires_in && this.isValidTicket(this)) {
return Promise.resolve({ ticket: this.ticket, ticket_expires_in: this.ticket_expires_in })
}
return this.readTicket()
.then(async res => {
// 判断是否过期
if (this.isValidTicket(res)) {
// 没有过期直接返回
return Promise.resolve(res)
} else {
// 过期调用接口请求
const data = await this.getTicket()
// 保存
this.saveTicket(data)
// 返回
return Promise.resolve(data)
}
})
.catch(async err => {
// 本地文件没有保存
const data = await this.getTicket()
// 保存
this.saveTicket(data)
// 返回
return Promise.resolve(data)
})
.then(res => {
// 这里主要是将相关信息放到实例对象上
const { expires_in, ticket } = res
this.ticket_expires_in = expires_in
this.ticket = ticket
return Promise.resolve(res)
})
}
acesstoken
的方法一共写了getTicket
、saveTicket
、readTicket
、isValidTicket
、fetchTicket
这5个方法,其中的逻辑比较简单utils.js
文件夹下,并写上了如下的方法const { resolve } = require("path")
const { readFile, writeFile } = require("fs")
module.exports = {
//...
writeFileAsync(data, fileName) {
const filePath = resolve(__dirname, fileName) // 传入绝对路径
const data_str = JSON.stringify(data)
return new Promise((resolve, reject) => {
writeFile(filePath, data_str, err => {
if (!err) {
resolve()
} else {
reject(err)
}
})
})
},
readFileAsync(fileName) {
const filePath = resolve(__dirname, fileName) // 传入绝对路径,__dirname:获取当前文件所在的路径
return new Promise((resolve, reject) => {
readFile(filePath, (err, data) => {
if (!err) {
// 转化为js对象
data = data.toString()
data = JSON.parse(data)
resolve(data)
} else {
reject(err)
}
})
})
}
}
在项目中的使用
const { readFileAsync, writeFileAsync } = require("../libs/utils")
// 保存jsapi_ticket的方法
saveTicket(ticket) {
return writeFileAsync(ticket,"ticket.txt")
}
// 读取access_token的方法
readTicket() {
return readFileAsync("ticket.txt")
}
utils.js
的文件夹下,所以就写了__dirname
来获取当前的文件ticket.txt
就放到了utils.js
所在的文件夹下