需求背景:
现有两个项目,A、B ,A项目作为B的一个子系统使用。
现从B中进入A的入口逻辑是:
1. B点击进入到A,A项目检测当前系统是未登录的状态,接口返回错误code值与登录地址URL,web拿到URL进行跳转。
2. URL是B给A提供的免登录地址,跳转到这个地址B做个两件事情:a. 返回一个登录令牌token b. 重定向到A项目的地址并且附带着token
3. 再次进入到A项目中,axios的请求拦截器中获取下location.href地址中携带的token信息,并将其放在请求header中
4. 后台拿到请求的接口的header中的token去验证是否合法,合法则正常返回。
由第4步,引出了一个问题。
A项目一开始会去请求一个系统行的接口getSystem,token也是放在这个接口的header中的,但是首页一开始加载不止这一个接口,会同时请求四个接口。那么有接口在getSystem请求返回正确的信息之前就请求了,就又会验证失败,然后又到了第1步的跳转。这样就会一直循环页面的跳转,无法正常使用A
解决方式
利用axios拦截器,对接口进行等待,当getSystem接口返回信息之前,所有的请求接口都被拦截。当返回了信息,被拦截的接口再继续请求。
axiosManage.js:
import store from '@/store'
//全局标识符,标志着获取到了system信息,影响到每一个请求接口
let pendingFlag = '';
//getSystemInfo接口请求成功后,会将信息保存到Vuex中
const getSystemInfo = ()=>store.getters.systemInfo
const waitSystemInfo =async function(){
//gotInfo代表已经正常返回信息了,没必要拦截,直接返回成功的peomise
if(pendingFlag==='gotInfo') return Promise.resolve() return new Promise((resolve, reject) => {
//轮询着去获取systemInfo信息,如果获取到了logFlag证明接口返回内容了
//此时就清除定时器,直接返回resolve,成功的promise
//如果没有获取到,什么都不处理,外层就是一个pending状态的promise
//这里的pendingFlag比较重要,如果没有这个全局标志,那么无法影响到每一个被拦截的接口 let intervel= setInterval(() => { let {logFlag}=getSystemInfo(); if(logFlag){ clearInterval(intervel) pendingFlag='gotInfo'; resolve(); } },500); })}
export async function post (url, params) {
if(url!=='/api/getSystemInfo'){
//这里利用await的语法糖性质:等待promise的状态修改之后,才继续往下走,
//如果方法返回一个pending状态的promise,那逻辑会一直在这里等待
//一旦pendingFlag变为gotInfo,每一个拦截的请求接口都会在这里被放开,逻辑向下走 await waitSystemInfo (); } return new Promise((resolve, reject) => { instance .post(url, params, showLoading) .then( ... ) .catch(err => { reject(err.data) }) .finally(err => { ... }) })}