一、问题引入

当用户发起一个请求时,判断token是否已过期,若已过期则先调refreshToken接口,拿到新的token后再继续执行之前的请求。

难点:当同时发起多个请求,token 过期会调用多次更新 token 接口;此时刷新token的接口还没返回,此时其他请求该如何处理,在刷新token接口返回后才能续订请求

二、取消重复请求

针对同时发起多个请求,token 过期会调用多次更新 token 接口,这里只做了取消重复请求操作,未能续订之前请求

维护一个 请求列表 reqList

在 axios 请求拦截器中判断请求是否已经在 reqList  中存在,存在则调用 axios.CancelToken 取消请求

// 正在进行中的请求列表
let reqList = [] /**
* 阻止重复请求
* @param {array} reqList - 请求缓存列表
* @param {string} url - 当前请求地址
* @param {function} cancel - 请求中断函数
* @param {string} errorMessage - 请求中断时需要显示的错误信息
*/
const stopRepeatRequest = function (reqList, url, cancel, errorMessage) {
const errorMsg = errorMessage || ''
for (let i = 0; i < reqList.length; i++) {
if (reqList[i] === url) {
cancel(errorMsg)
return
}
}
reqList.push(url)
} /**
* 允许某个请求可以继续进行
* @param {array} reqList 全部请求列表
* @param {string} url 请求地址
*/
const allowRequest = function (reqList, url) {
for (let i = 0; i < reqList.length; i++) {
if (reqList[i] === url) {
reqList.splice(i, 1)
break
}
}
} const service = axios.create() // 请求拦截器
service.interceptors.request.use(
config => {
let cancel
// 设置cancelToken对象
config.cancelToken = new axios.CancelToken(function(c) {
cancel = c
})
// 阻止重复请求。当上个请求未完成时,相同的请求不会进行
stopRepeatRequest(reqList, config.url, cancel, `${config.url} 请求被中断`)
return config
},
err => Promise.reject(err)
) // 响应拦截器
service.interceptors.response.use(
response => {
// 增加延迟,相同请求不得在短时间内重复发送
setTimeout(() => {
allowRequest(reqList, response.config.url)
}, 1000)
// ...请求成功后的后续操作
// successHandler(response)
},
error => {
if (axios.isCancel(thrown)) {
console.log(thrown.message);
} else {
// 增加延迟,相同请求不得在短时间内重复发送
setTimeout(() => {
allowRequest(reqList, error.config.url)
}, 1000)
}
// ...请求失败后的后续操作
// errorHandler(error)
}
)

三、更新token并续订上次请求

此方法可用于多个请求token失效,进行多次更新 token 请求操作时,取消其他更新 token 请求,并在完成更新后续订上次多个请求

// 是否正在刷新的标记
let isRefreshing = false
// 重试队列,每一项将是一个待执行的函数形式
let retryRequests = [] // 请求拦截
service.interceptors.request.use(
config => {
const token = localStorage.getItem('access_token')
if (token && !config.url.includes('/oauth/token')) {
config.headers.Authorization = 'Bearer ' + token;
}
if (config.method === 'post' || config.method === 'put') {
config.data = qs.stringify(config.data);
}
return config;
},
err => {
return Promise.reject(err);
}
); // 响应拦截
service.interceptors.response.use(
async response => {
if (response.status === 200) {
if (response.data && response.data.code == 4001) {
const config = response.config
if (!isRefreshing) {
isRefreshing = true
// const refresh_token = localStorage.getItem('refresh_token')
// const token = localStorage.getItem('access_token')
try {
const result = await getToken({
grant_type: 'password',
client_id: 'client-app',
client_secret: '123',
username: 'sunhj',
password: '123'
})
localStorage.setItem('access_token', result.token || '')
// localStorage.setItem('refresh_token', res.refreshToken || '')
const token = localStorage.getItem('access_token')
config.headers['Authorization'] = 'Bearer ' + token
// 已经刷新了token,将所有队列中的请求进行重试
retryRequests.forEach(cb => cb('Bearer ' + token))
// 重试完清空这个队列
retryRequests = []
// 这边不需要baseURL是因为会重新请求url,url中已经包含baseURL的部分了
config.baseURL = proxyHost
if (config.method === 'post' || config.method === 'put') {
config.data = qs.parse(config.data)
}
isRefreshing = false
return service(config)
} catch (error) {
isRefreshing = false
}
} else {
// 正在刷新token,返回一个未执行resolve的promise
return new Promise((resolve) => {
// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
retryRequests.push((token) => {
config.baseURL = proxyHost
config.headers['Authorization'] = token
if (config.method === 'post' || config.method === 'put') {
config.data = qs.parse(config.data)
}
resolve(service(config))
})
})
}
} else {
// 二进制流文件下载
if (response.headers['content-type'] === "application/octet-stream;charset=UTF-8") {
return response;
} else {
return response.data;
}
}
} else {
Promise.reject();
}
},
err => {
return Promise.reject(err);
}
);

参考:https://blog.csdn.net/weixin_45178716/article/details/103286459

axios取消重复请求与更新token并续订上次请求的更多相关文章

  1. axios 取消请求

    解决思路 在发送第二次请求的时候如果第一次请求还未返回,则取消第一次请求,以保证后发送的请求返回的数据不会被先发送的请求覆盖. axios官方文档取消请求说明 方法一: const CancelTok ...

  2. 从 axios 源码中了解到的 Promise 链与请求的取消

    axios 中一个请求取消的示例: axios 取消请求的示例代码 import React, { useState, useEffect } from "react"; impo ...

  3. axios构建请求池处理全局loading状态&&axios避免重复请求

    很多时候我们能够看到类似进度条一样的东西在页面顶部进行加载,代表页面是否加载完成,或者其他的loading效果,我们当然不可能通过promise.all来讲所有的请求合并到一起然后进行处理,这个时候我 ...

  4. axios取消接口请求

    axios取消请求 这里就是分析一下接口请求需要被取消时的一些操作 因为我是用vue写的项目,所以标配用的是axios,怎么在axios中取消已经发送的请求呢? 1.在这之前我们还是先介绍一下原生js ...

  5. axios 取消请求的方法

    开发中遇到需要取消请求的功能,,点击终止查询可以取消开始查询请求,再次点击开始查询又可以进行查询. 解决方法:axios官方文档上的CancelToken,一开始用了这个api后,可以成功取消请求,但 ...

  6. axios中为所有请求带上Token头

    axios中为所有请求带上Token头 https://www.imooc.com/article/27751

  7. Axios 取消 Ajax 请求

    Axios 取消 Ajax 请求 Axios XMLHttpRequest https://caniuse.com/?search=XMLHttpRequest https://developer.m ...

  8. 学习AJAX必知必会(3)~自动重启工具nodemon、缓存问题、请求超时和网络异常、取消重复请求

    1.nodemon 自动重启工具(自动重启基于nodejs开发的服务端应用) ■ nodemon 是一个工具,通过在检测到目录中的文件更改时自动重新启动node应用程序来帮助开发node.js. // ...

  9. axios 访问和返回拦截,token处理,返回异常统一处理

    在axios文件夹中,index.js添加拦截 访问拦截: import store from '../store' axios.interceptors.request.use( config =& ...

  10. axios interceptors 拦截 , 页面跳转, token 验证 Vue+axios实现登陆拦截,axios封装(报错,鉴权,跳转,拦截,提示)

    Vue+axios实现登陆拦截,axios封装(报错,鉴权,跳转,拦截,提示) :https://blog.csdn.net/H1069495874/article/details/80057107 ...

随机推荐

  1. linux环境下mariadb10.5.16的数据存储目录修改

    mysql或mariadb的数据,一般默认存在/var/lib/mysql目录下,本文介绍把mariadb数据存到容量较大的目录中,如/home 操作步骤: 1.将/var/lib/mysql的数据复 ...

  2. 5.mysql的explain的分析

    执行分析:  1.id 含义:表示查询的子句或者操作表的顺序 三种情况:id 相同,执行的顺序由上到下: id不同,id越大优先级越高,越先执行: id相同不相同同时存在: 2.select_type ...

  3. jmeter安装配置

    #前提需要有java的环境变量JAVA_HOME=/usr/local/java#jmeter变量CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/t ...

  4. PID模板

    typedef struct{ float Kp,Ki,Kd; float Target; float Current; float Error[3]; float DeadZone; float O ...

  5. django解决网站CORS前后端跨域问题

    1.安装cors-headers⼯具   pip install django-cors-headers 2.安装cors-headers应⽤ # 注册应用 INSTALLED_APPS = [ 'd ...

  6. 从零搭建hadoop集群之克隆虚拟机

    1. 选中一台已关闭的虚拟机,在虚拟机名称上,右键点击,选择"管理",再选择"克隆", 出现如下画面: 2. 点击"下一步",出现如下画面: ...

  7. 浅谈JS中的element.style和window.getComputedStyle()的区别

    MDN对于element.style的解释 被高光的句子中的inline style属性是指css内联样式,即元素的style属性的属性值 总结一下,element.style只能获取到元素的styl ...

  8. wsl 的 tail -f 不好使

    windows 上的sub linux ubuntu 的tail -f 不好使 在/etc/profile 中加入alias alias tailf='tail -f ---disable-inoti ...

  9. C# goto 语法

    test: Console.WriteLine("yest"); goto test;

  10. ComPiler200003:Story-Oriented Programming

    Story-Oriented Programming MAY 25TH, 2018 http://www.brandonkeown.com/2018/05/story-oriented-program ...