背景
Token 通常用于用户认证和权限管理,当 Token 过期时一般会重定向到登录页,用户的操作会受到影响,因此需要无感刷新。以下用双token实现。
原理
每次发起请求时,检查访问令牌的有效性。
如果访问令牌过期,暂停当前请求并使用刷新令牌获取新的访问令牌。
使用新的访问令牌重新发起之前被暂停的请求。
更新应用中的 Token 信息。
以上原理是其他博客里看到的描述,但是在他们的代码里,都没有暂停请求,只是存储了失败的请求。
vue+axios场景下实现无感刷新
// 创建axios实例
1 2 3 4
| const service = Axios.create({ baseURL, timeout: 30000 })
|
// 新增请求拦截器,主要用于请求前带上token
1 2 3 4 5 6 7 8 9 10 11
| service.interceptors.request.use( async config => { config.headers['token'] = getStorage('token') return config }, error => { return Promise.reject(error) } )
|
// 新增响应拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| service.interceptors.response.use( async (res) => { if (res.code === 100) { const methodMap = { get: $get, post: $post, put: $put, del: $del } const method = methodMap[res.config.method] const url = res.config.url let data = res.config.data
await store.dispatch('system/execRefreshToken') return method(url, data) } else { ... }
}, err => { return Promise.reject(err) } )
|
// 刷新部分
如果多个接口用过期的token,都会进入此方法,为了防止重复调用刷新,设置了promise,能适用于大部分情况
注:但是这个promise只能在刷新时防止重复,试想如果有个接口(用了过期token的)响应很慢,在刷新完token后,promise置null了,才进入响应拦截器,这时就又会调用一遍刷新。
TODO:1.promise置null加个延迟,能防止大部分情况。2.刷新后再设置个变量,短时间内用来判断是否已经刷新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| let promise = null execRefreshToken() { if(promise) return promise promise = new Promise((resolve, reject) => { const token = getStorage('token') const refreshToken = getStorage('refreshToken') const params = { token, refreshToken } $post(api.sysLoginRefreshToken, params).then(res => { setStorage('token', res.token) setStorage('refreshToken', res.refreshToken) resolve(res) }).catch(err => { reject(err) }) }) promise.finally(() => { promise = null }) return promise }
|