前端实现token无感刷新的原因和步骤
前端实现无感刷新
需要这么做的原因
在使用过程中,如果token过期,再操作页面可能就需要重新返回登录页获取token了,在持续使用的过程中可能会出现多次跳去登录页的情况,用户体验很不好。所以需要做无感刷新
做token无感刷新的方式
使用双token:access_token(权限token)和refresh_token(用于获取新token的刷新token)
方式一:在响应器中拦截,判断access_token返回过期后,调用refresh_token的接口,获取新token,覆盖原access_token
方式二:后端返回access_token时间,让前端判断是否过期,如果过期则调用refresh_token的接口,刷新token
方式三:通过定时器,定时刷新access_token
通常是采用方式一去实现
弊端:方式二需要后端额外返回access_token过期时间字段,而且如果前端电脑本地时间被篡改,则无法正确判断access_token是否过期。方式三使用定时器会增加页面的开销影响性能
实现流程
1、登录后返回两个token,分别为权限access_token和refresh_token
2、在响应拦截器中对返回401(无权限状态码)时,通过refresh_token调用token刷新接口
3、替换本地已过期的access_token
4、把刚刚失败的请求(返回的错误对象)中的access_token替换掉
5、再次发送刚刚未能完成的请求。
注:如果refresh_token也过期了,那么则需要清除掉所有token(access_token和refresh_token),返回登录页登录。在刷新access_token的同时,最好也能刷新refresh_token,比如refresh_token设置过期为7天,刷新一次access_token后把refresh_token又往后续了7天。这也是为什么很多软件登录后几乎不用再登录的原因。
提示:在刷新access_token的时候,建议设置一个标识变量用于标识access_token是否已经刷新了,毕竟过期时发起的请求可能有多条,响应拦截后没必要重复刷新access_token,而且重复刷新acces_token可能会报错,因为最先执行完的刷新请求已经将refresh_token 更新了,而后面执行的刷新请求还是使用旧的refresh_token
避免重复刷新的示例
let isRefreshing = false; // 是否刷新中
let promiseRe;
export function refreshToken() {
if(isRefreshing) { // 正在刷新中
return promiseRe
}
isRefreshing = true; // 第一个触发刷新的,将标识置true
promiseRe = request({ // 第一个刷新返回一个promise,后续有同时期提起刷新的,依旧直接对请求返回此promise,避免重复发起请求
url: '/refreshToken',
methods: 'post',
data: { refreshToken: refresh_token}
})
.finally(() => {
isFreshing = false; // 请求执行完毕后,无论成功与否,都将标识置false,避免后续提起刷新时直接进if中,无法正常刷新token
})
return promiseRe
}