前言
最近在做需要的时候,波及到登录token,产品提出一个问题:能不能让token过期工夫长一点,我频繁的要去登录。
前端:后端,你能不能把token 过期工夫设置的长一点。
后端:能够,然而那样做不平安,你能够用更好的办法。
前端:什么办法?
后端:给你刷新token的接口,定时去刷新token
前端:好,让我思考一下
需要
当token过期的时候,刷新token,前端须要做到无感刷新token,即刷token时要做到用户无感知,防止频繁登录。实现思路
办法一
后端返回过期工夫,前端判断token过期工夫,去调用刷新token接口
毛病:须要后端额定提供一个token过期工夫的字段;应用了本地工夫判断,若本地工夫被篡改,特地是本地工夫比服务器工夫慢时,拦挡会失败。
办法二
写个定时器,定时刷新token接口
毛病:浪费资源,耗费性能,不倡议采纳。
办法三
在响应拦截器中拦挡,判断token 返回过期后,调用刷新token接口
实现
axios的根本骨架,利用service.interceptors.response进行拦挡
import axios from 'axios'
service.interceptors.response.use(
response => {
if (response.data.code === 409) {
return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
const { token } = res.data
setToken(token)
response.headers.Authorization = `${token}`
}).catch(err => {
removeToken()
router.push('/login')
return Promise.reject(err)
})
}
return response && response.data
},
(error) => {
Message.error(error.response.data.msg)
return Promise.reject(error)
})
复制代码
问题解决
问题一:如何避免屡次刷新token
咱们通过一个变量isRefreshing 去管制是否在刷新token的状态。
import axios from 'axios'
service.interceptors.response.use(
response => {
if (response.data.code === 409) {
if (!isRefreshing) {
isRefreshing = true
return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
const { token } = res.data
setToken(token)
response.headers.Authorization = `${token}`
}).catch(err => {
removeToken()
router.push('/login')
return Promise.reject(err)
}).finally(() => {
isRefreshing = false
})
}
}
return response && response.data
},
(error) => {
Message.error(error.response.data.msg)
return Promise.reject(error)
})
复制代码
问题二:同时发动两个或者两个以上的申请时,其余接口怎么解决
当第二个过期的申请进来,token正在刷新,咱们先将这个申请存到一个数组队列中,想方法让这个申请处于期待中,始终等到刷新token后再一一重试清空申请队列。那么如何做到让这个申请处于期待中呢?为了解决这个问题,咱们得借助Promise。将申请存进队列中后,同时返回一个Promise,让这个Promise始终处于Pending状态(即不调用resolve),此时这个申请就会始终等啊等,只有咱们不执行resolve,这个申请就会始终在期待。当刷新申请的接口返回来后,咱们再调用resolve,一一重试。最终代码:
import axios from 'axios'
// 是否正在刷新的标记
let isRefreshing = false
//重试队列
let requests = []
service.interceptors.response.use(
response => {
//约定code 409 token 过期
if (response.data.code === 409) {
if (!isRefreshing) {
isRefreshing = true
//调用刷新token的接口
return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
const { token } = res.data
// 替换token
setToken(token)
response.headers.Authorization = `${token}`
}).catch(err => {
//跳到登录页
removeToken()
router.push('/login')
return Promise.reject(err)
}).finally(() => {
isRefreshing = false
})
} else {
// 返回未执行 resolve 的 Promise
return new Promise(resolve => {
// 用函数模式将 resolve 存入,期待刷新后再执行
requests.push(token => {
response.headers.Authorization = `${token}`
resolve(service(response.config))
})
})
}
}
return response && response.data
},
(error) => {
Message.error(error.response.data.msg)
return Promise.reject(error)
})
复制代码
总结
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163互相学习,咱们会有业余的技术答疑解惑
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点star: http://github.crmeb.net/u/defu 不胜感激 !
发表回复