一、Axios简介
Axios基于promise的网络请求库,作用于node.js和浏览器。
在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
特性:
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求,本文使用到的api
- 自动转换JSON数据
- 客户端支持防御XSRF
二、实现
import axios from 'axios'
/*客户端发起的请求合集*/
const ajaxExecutingMap = new Map()
/**
* @desc 构建请求合集所用key
* @param url 当前请求的url
* @param data 当前请求的所有入参
* @param requestMethod 请求方法以及数据传输方式
*/
const buildAjaxKey = (url, data, requestMethod) => {
const ajaxKey = `${requestMethod}: ${url}-${JSON.stringify(data)}`
return {
ajaxKey
}
}
/**
* @desc 清除请求合集中已返回的请求
* @param config 请求的config属性
*/
const clearFinishAjax = (config) => {
let { url, data, params, method } = config
const reqData = data ? JSON.parse(data) : {}
const reqParams = params ? JSON.parse(params) : {}
const configData = {
...reqData,
...reqParams
}
const { ajaxKey } = buildAjaxKey(url, configData, method)
if (ajaxExecutingMap.get(ajaxKey)) {
ajaxExecutingMap.delete(ajaxKey)
}
}
/**
* @desc 处理重复请求
* @param config 请求的config属性
*/
const dealReplayModel = (config) => {
// 调用axios的取消请求方法
const CancelToken = axios.CancelToken
const { data, params, method, url, antiReplayModel } = config
const paramsData = {
...data,
...params
}
const { ajaxKey } = buildAjaxKey(url, paramsData, method)
const oldAjaxCanceler = ajaxExecutingMap.get(ajaxKey)
if (oldAjaxCanceler) {
/* 丢弃新请求 */
if (antiReplayModel) {
return {
executeAjax: false, /* 不执行当前请求 */
config
}
} else {
/* 取消旧请求 */
oldAjaxCanceler.cancelSource.cancel(`旧的请求: ${ajaxKey} 被取消`)
/* 将请求合集旧的请求数据进行删除 */
ajaxExecutingMap.delete(ajaxKey)
}
}
/* 将新的请求存储到请求合集 */
const cancelSource = CancelToken.source()
ajaxExecutingMap.set(ajaxKey, {
cancelSource
})
config.cancelToken = cancelSource.token
return {
executeAjax: true, /* 执行当前请求 */
config
}
}
const httpService = axios.create()
httpService.interceptors.request.use((config) => {
/* 重复请求拦截,如果配置antiReplayModel为true,则重复的情况下丢弃新请求,若为false,则重复的情况下取消旧请求,其他情况不做处理 */
if (typeof config.antiReplayModel === 'boolean') {
const antiReplayObj = dealRepeatModel(config)
if (!antiReplayObj.executeAjax) {
return Promise.reject(new Error(`请求重复 ${config.url}`))
}
config = antiReplayObj.config
}
})
httpService.interceptors.response.use((response) => {
/* 若有重复请求拦截,则这里处理结束拦截 */
if (typeof response.config.antiReplayModel === 'boolean') {
clearFinishAjax(response.config)
}
},(error) => {
/* 在这里查看重复处理过程中抛出的提示 */
console.log(error)
})
/* 举个例子 */
httpService({
url: 'api/get',
method: 'post',
data: {},
antiReplayModel: true
})