Token无缝刷新
前后端分离的系统,假如这个系统是给客服人员使用,客服人员可能要在长达八个小时的时间上不停地工作;为了安全考虑,不给token设定永久的时常,而是给它一个可刷新时间区域:在当前token刚刚过期后的一段时间发起的请求,系统可以无缝刷新一次token,从而为使用者带来更好的体验,这是非常重要的。
Axios中的实现
原理简单阐述
实现很简单,在拦截器当中检测返回数据,检测到刚刚过期可以刷新的情况,则在拦截器中直接发起刷新token的请求,获得到新token后保存,再执行一次失败的请求,执行完毕返回。
会遇到的问题
axios是异步执行的,假如在刷新token的过程中又有其他携带旧token并收到需要刷新的标识后,又如何处理呢?
设置一个全局标识,表明当前是否正在刷新token,如果正在刷新,就拒绝。这样显然是不好的。在一次需求中可能要发起多个请求这是很正常的事情。为了不让其他请求失败,我的做法是,创建一个异步任务顺序执行器,在刷新token期间还携带旧token并返回过期的请求,则重新将本请求加入到这个执行器的末尾;而执行器则是在首次检测到过期时进行初始化,并开始执行第一个任务,也就是刷新token任务。
代码
放代码之前我先给出一些解释:我并没有使用常规的http状态码来判断响应结果,而是在后端程序中讲所有非系统错误的大部分异常全部封装为了自定义的错误码并返回给前台,我在拦截器中自己来判断返回结果。
/* eslint-disable no-unused-vars */
'use strict'
import Vue from 'vue'
import axios from 'axios'
import router from '../router.js'
import {
Notification, Message } from 'element-ui'
// Full config: https://github.com/axios/axios#request-config
// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || ''
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
let config = {
// baseURL: process.env.baseURL || process.env.apiUrl || ''
// timeout: 60 * 1000, // Timeout
// withCredentials: true, // Check cross-site Access-Control,
}
const _axios = axios.create(config)
_axios.interceptors.request.use(
function (config) {
// Do something before request is sent
if (!config.url.includes('http')) {
config.url = 'http://127.0.0.1:4399' + config.url
}
const token = localStorage.getItem('token')
if (token) {
co