Wang's blog Wang's blog
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Wang Mings

跟随大神,成为大神!
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • CSS

  • Npm

  • Vue

    • Vue简介
    • 路由守卫
    • tsvue的写法
    • Vue常用技巧
    • vue的JSX写法
    • vue防抖组件
    • 动态热更新设置
    • keepActive缓存路由
    • 自动生成面包屑VUE组件
    • vue生命周期对比生命周期
    • eslint编译时警告或错误配置
    • Vue中封装axios的取消请求事情
      • 前言
      • axios本身就封装了取消事件
        • axios取消事件代码如下
        • 单独使用axios的时候,两个方法都可以,但是封装好axios方法在vue中全局调用时,方法一有个问题,axios的cancel方法会把即将要发出的请求取消掉,所以用第二个方法
      • 完整axios封装代码如下:
    • vue+element递归生成无限菜单组件
    • Vue框架dist目录下各个文件的区别
    • 超详细Vue的种和Vue的种组件间通信方式
    • Vue项目中出现Loadingchunk{n}failed问题的解决方法
    • Vuex

    • 其他

    • 基础

    • 工具

    • 组件

    • 规模化

    • 过渡&动画

    • 可复用性&组合

  • HTML

  • Node

  • Yaml

  • React

  • 框架

  • 规范

  • Electron

  • JS演示

  • VuePress

  • JavaScript

  • TypeScript

  • 微信小程序

  • TypeScript-axios

  • 前端
  • Vue
wangmings
2022-07-19
目录

Vue中封装axios的取消请求事情

# Vue中封装axios的取消请求事情

# 前言

需要取消重复请求的场景:

  • 比如输入框搜索需要取消上一次的重复请求
  • tab切换频繁获取数据列表接口时,接口重复请求
  • 就是用户频繁切换操作时,我们调用都是同一个接口的时候,就需求先取消上一次的接口请求,只请求用户最后一次操作的接口,不然相同的接口重复请求,接口是异步的,到时就容易拿到数据不是最后一次操作想要的数据了

# axios本身就封装了取消事件

axios中文文档 取消事件 (opens new window)

# axios取消事件代码如下

  • 方法一、可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
     // 处理错误
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • 方法二、还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    cancel = c;
  })
});

// cancel the request
cancel();
1
2
3
4
5
6
7
8
9
10
11
12

# 单独使用axios的时候,两个方法都可以,但是封装好axios方法在vue中全局调用时,方法一有个问题,axios的cancel方法会把即将要发出的请求取消掉,所以用第二个方法

# 完整axios封装代码如下:

import axios from 'axios'
import UserModel from '../models/user'

// 接口前缀
const PREFIX = {
  mock: 'https://yapi.comliq.net/mock/31/', // yapi mock 地址
  development: 'http://xxx/', // qa环境
  production: 'http://xxx/', // 生产环境
}
const env = process.env.NODE_ENV
let interfacePrefix = PREFIX[env] || PREFIX.production // 接口前缀

/**
 * config 自定义配置项
 * @param withoutCheck 不使用默认的接口状态校验,直接返回 response
 * @param returnOrigin 是否返回整个 response 对象,为 false 只返回 response.data
 * @param mock 是否使用 mock 服务
 * @param timeout 接口请求超时时间,默认10秒
 * @param isCancelRequest 是否可以取消请求
 */
const configDefault = {
  returnOrigin: false,
  withoutCheck: false,
  mock: false,
  timeout: 10000
}

// 创建请求器
const service = axios.create(Object.assign({
  baseURL: '',
  responseType: 'json',
  headers: {
    'Content-Type': 'application/json;charset=utf-8',
  },
}, configDefault))


// 添加请求拦截器
service.interceptors.request.use(
  request => {
    const reqData = request.data || request.params
    if (reqData && !request.canEmpty) { // 对请求参数进行处理,清除空参数
      request.data = deleteEmpty(reqData)
    }

    // 检测接口,根据环境自动切换前缀
    if (request.url.indexOf('http') === -1) {
      if (request.url[0] === '/') {
        request.url = request.url.substr(1)
      }
      request.url = `${env !== 'production' && request.mock ? PREFIX.mock : interfacePrefix}${request.url}`
    }

    // 若有做鉴权token,需要请求头自动加上token, 这个token自己封装获取的
    request.headers.accessToken = UserModel.getToken()

    return request
  },
  error => {
    return Promise.reject(error)
  },
)

// object对象存放每次new CancelToken生成的方法
let source = {}

// 每次请求前都会把path放在此数组中,响应成功后清除此请求path
let requestList = []

// 定义取消方法
function cancelRequest(path, allCancel) {
  // 请求列表里存在此path,即发起重复请求,把之前的请求取消掉
  if (path && requestList.includes(path) && typeof source[path] === 'function') {
    source[path]('终止请求')
  } else if (!path && allCancel) {
    // allCancel为true则请求列表里的请求全部取消
    requestList.forEach(el => {
      source[el]('批量终止请求')
    })
  }
}

// 添加响应拦截器
service.interceptors.response.use(
  res => {
    // 获取请求的api
    const path = JSON.stringify(res.config.url)
    // 请求完成后,将此请求从请求列表中移除
    requestList = requestList.filter(item => !path.includes(item))
    // HTTP 状态码 2xx 状态入口,data.code 为 200 表示数据正确,无任何错误
  },
  error => { // 非 2xx 状态入口
    return Promise.reject(error)
  },
)

// 这里只做post封装演示,大家可以自己封装其他请求方法
function requestFn(method, path, params = {}, options = {}) {
  // 取消上一次请求
  if (requestList.length) {
    cancelRequest(path)
  }
  // 设置isCancelRequest为ture, 请求前将path推入requestList
  if (options.isCancelRequest) {
    requestList.push(path)
  }

  if (method === 'post') {
    return service.post(path, params, {
      cancelToken: new axios.CancelToken(c => {
        source[path] = c
      }),
      ...options
    })
  }
}

export const api = {
  axios: service, // 原始 axios 对象

  // 重新封装 get 函数,统一使用方式
  get: (path, data, config) => service.get(path, { params: data, ...config }),
  delete: (path, data, config) => service.delete(path, { data, ...config }),

  post: (path, data, config) => requestFn('post', path, data, config),
  put: (path, data, config) => service.put(path, data, config),
}

export default api
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

参考文献:

Vue中封装带有取消请求的axios (opens new window)

编辑 (opens new window)
eslint编译时警告或错误配置
vue+element递归生成无限菜单组件

← eslint编译时警告或错误配置 vue+element递归生成无限菜单组件→

最近更新
01
theme-vdoing-blog博客静态编译问题
09-16
02
搜索引擎
07-19
03
友情链接
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式