前言
最近在开发后天管理系统时增加了一个token失效以后不返登录页面而是在当前页面用旧的token去服务器换新的token,成功后拿到新的token去发被挂起的请求。这样对于我这样的前端没接触过完全是个坑啊,废话不多说开始正文。
我先贴出代码
/*token失效请求次数*/
window.error = false
/*被挂起的请求数组*/
let refreshSubscribers = [];
/*push所有请求到数组中*/
function subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
/*刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据)*/
function onRrefreshed(token) {
refreshSubscribers.map(cb => cb(token));
}
// 响应拦截器
service.interceptors.response.use(
response => {
if (response.headers["content-disposition"]) {
return response;
}
if (response.data.code == 200) {
return response.data;
} else if(response.data.code == 4001{
return reloadMessage(response.config)
}else {
/* 4001 短token过期 error防止多个网络请求同事报错 */
if(!window.error){
window.error = true
vm.$warning({title: `登录失效,请重新登录`});
Vue.ls.set('isLogin', false)
Vue.ls.remove('userInfo')
window.router.push("/login");
}
}
/* 消息重发 */
function reloadMessage(config){
refreshToken().then(res =>{
var tempdate = new Date().format('Y.MM.dd h:m:s')
console.log(`更token时间${tempdate};\n新的toke${res.result.token}`)
/*成功刷新token*/
config.headers['Authorization'] = res.result.token
/*更新本地的token*/
Vue.ls.set('authorization',res.result.token)
Vue.ls.set('refreshToken',res.result.RefreshToken)
/*执行数组里的函数,重新发起被挂起的请求*/
onRrefreshed(res.result.token)
/*执行onRefreshed函数后清空数组中保存的请求*/
refreshSubscribers = []
})
/*将请求挂起*/
let retry = new Promise((resolve, reject) => {
/*(token) => {...}这个函数就是回调函数*/
subscribeTokenRefresh(token => {
console.log("重发token is", token.substr(-4));
config.headers["Authorization"] = token;
axios.request(config).then(res =>{
window.requestCount = 0
resolve(res.data)
})
});
});
return retry;
}
在开始之前我们应该先知道几个问题?
1.token刷新应该是在js的响应拦截器里做的
2.至于应该是请求发送前判断token失效,还是在token已经失效的时候发送刷新token的请求。其实我感觉在token失效的时候做这个操作是挺好的一种方式,因为你不知道用户可能隔了多长时间去做这个操作,如果隔的时间比较久,这个时候可能就不是很适合继续去刷新token而是返回登录页面。因为这样也许会安全和更合适一些。
1.首先先声明数组,用来挂起的网络请求;如果有网络请求token过期的话就把这个网络请求放到数组里。(这里比较惭愧在学习js的时候竟然不知道可以把数组里面放入请求,当时在网上看到这个骚操作内心一万个曹尼玛飞奔而过)
/*被挂起的请求数组*/
let refreshSubscribers = [];
/*push所有请求到数组中*/
function subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
/*将请求挂起*/
let retry = new Promise((resolve, reject) => {
/*(token) => {...}这个函数就是回调函数*/
subscribeTokenRefresh(token => {
console.log("重发token is", token.substr(-4));
config.headers["Authorization"] = token;
axios.request(config).then(res =>{
resolve(res.data)
})
});
});
return retry;
2.然后呢就是发送更新token的操作了,换取成功后会更新LocalStorage
里的token
/* 消息重发 */
function reloadMessage(config){
refreshToken().then(res =>{
var tempdate = new Date().format('Y.MM.dd h:m:s')
console.log(`更token时间${tempdate};\n新的toke${res.result.token}`)
/*成功刷新token*/
config.headers['Authorization'] = res.result.token
/*更新本地的token*/
Vue.ls.set('authorization',res.result.token)
Vue.ls.set('refreshToken',res.result.RefreshToken)
/*执行数组里的函数,重新发起被挂起的请求*/
onRrefreshed(res.result.token)
/*执行onRefreshed函数后清空数组中保存的请求*/
refreshSubscribers = []
})
/*将请求挂起*/
let retry = new Promise((resolve, reject) => {
/*(token) => {...}这个函数就是回调函数*/
subscribeTokenRefresh(token => {
console.log("重发token is", token.substr(-4));
config.headers["Authorization"] = token;
axios.request(config).then(res =>{
window.requestCount = 0
resolve(res.data)
})
});
});
return retry;
}
其中refreshToken()
这个方法就是用老的token换取新的token,因为token存在LocalStorage
里面所以直接拼到了地址后面,如果失败了就直接返回登录页面;token请求成功后,接下来就是把本地的token替换掉然后发送被挂起的网络请求onRrefreshed(res.result.token)
然后subscribeTokenRefresh
里面的异步回调。至此整个流程就已经完成了
虽然这只是一个很小的需求,但很考验开发者javascript的知识深度。感谢阅读
网友评论