一、问题引入

当用户发起一个请求时,判断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. Razor视图cshtml做到运行时编译【提高开发效率】

    当你的.NET开发工具升级到.NET Core版本以上,就会发现有时候无法将视图界面做的修改可以直接保存后刷新输出,一般都需要重新热重载或重新编译,这样会导致开发效率过慢的行为,开发者无法直接直观地看 ...

  2. 读后笔记 -- Python 全栈测试开发 Chapter7:移动自动化测试框架

    7.1 主流框架优缺点剖析 1. APP 主要测试策略 安装.卸载测试: 安装:1)安装路径:2)安装环境(平台.安全软件):3)安全权限(获取位置.摄像头.通讯录.ROOT管理员等权限):4)安装的 ...

  3. Wix Setting language and code page attributes

    When you localize your MSI package, you'll need to alter your Productand Package elements to suit. T ...

  4. 虚拟机中Linux分区扩容

    打开Virtualbox所在的安装目录,执行以下命令,命令中的虚拟有磁盘路径改成自己的: 调整容量前,先关闭虚拟机.接着,打开CMD,进入VirtualBox的安装目录,执行VBoxManage li ...

  5. linux源码-概览

    BootloaderWin    Bios Linux UbootAndroid fastboot linux源码宏观结构boot:启动linux时要用到的引导代码 bootsect.s 磁盘引导文件 ...

  6. 100多个常用 API 接口整理大全

    聚合数据提供30大类,160种以上基础数据API服务,国内最大的基础数据API服务,下面就罗列一些免费的各类API接口. 手机号码归属地API接口: https://www.juhe.cn/docs/ ...

  7. rest-assured:JUnit5中接口测试参数化的支持之利用EnumSource检查用户消息是否包含特定字段(JSON path $ doesn't match.)

    代码:package ghcdgj.restful.framework;import static org.junit.jupiter.api.Assertions.*;import static i ...

  8. Python学习笔记组织文件之shutil模块

    随笔记录方便自己和同路人查阅. #------------------------------------------------我是可耻的分割线--------------------------- ...

  9. HTTP对应状态码

    服务器–响应–客户端 1. 响应体 Accept:告诉浏览器所支持的数据类型Accept-Encoding:表示浏览器支持的编码格式 GBK UTF-8 GB2312 ISO8859-1Accept- ...

  10. k8s 更改pod数量限制(默认每个节点最多110组pod)

      1.登录 node 节点,查看kubelet启动文件路径 [root@xxxxxxxZ ~]# systemctl status kubelet ● kubelet.service - kubel ...