封装的必要性
我们在使用 axios 进行异步操作时, 可能会遇到以下情况:
对一个按钮频繁点击, 发送多次请求
axios 的规范写法中:
axios.post(url, data).then(res=>{}).catch(err=>{})
复制代码
这里我们发现我们每一次写的时候, 都需要写. catch(err=>{}), 会造成代码的冗余
封装过程
拦截器科普
- // 添加请求拦截器
- axios.interceptors.request.use(function (config) {
- // 在发送请求之前做些什么
- return config;
- }, function (error) {
- // 对请求错误做些什么
- return Promise.reject(error);
- });
- // 添加响应拦截器
- axios.interceptors.response.use(function (response) {
- // 对响应数据做点什么
- return response;
- }, function (error) {
- // 对响应错误做点什么
- return Promise.reject(error);
- });
复制代码
取消请求处理方法科普
- var CancelToken = axios.CancelToken;
- var cancel;
- axios.get('/user/12345', {
- cancelToken: new CancelToken(function executor(c) {
- // executor 函数接收一个 cancel 函数作为参数
- cancel = c;
- })
- });
- // 取消请求
- cancel();
复制代码
本文代码
axios.js
设置一个 cancelFlag 作为标志符, 默认为 true, 在请求拦截器时, 判断如果 cancelFlag 为 true, 就可以发送请求, 且将 cancelFlag 设为 false. 当 cancelFlag 为 false, 就取消请求. 在响应拦截器中再将 cancelFlag 设为 true. 说明只用当一个请求发送且收到响应后, 才可以发送另一个请求. 这里存在的问题: cancelFlag 是全局变量, 这样多页面多个接口请求时, 互相会有影响这里的解决办法就是在 axios.js 中构建构造函数, 这样可以让 cancelFlag 私有化, 但是这样的方式会导致占有大量内存. 参考同事写的代码, 我觉得非常的有道理. 而且比较简单.
版本一,
- import vue from 'vue'
- import axios from 'axios'
- import {Indicator} from 'mint-ui'
- Vue.component(Indicator)
- let CancelToken = axios.CancelToken // 取消请求
- let cancelFlag = true
- // 设置公共部分, 请求头和超时时间
- axios.defaults.headers = {
- 'X-Requested-With': 'XMLHttpRequest'
- }
- axios.defaults.timeout = 20000
- // 在请求拦截器时
- axios.interceptors.request.use(config => {
- if (cancelFlag) {
- cancelFlag = false
- Indicator.open()
- } else {
- cancelToken: new CancelToken (c => {
- cancel = c
- })
- cancel()
- }
- return config
- }, error => {
- return Promise.reject(error)
- })
复制代码
版本二, 异步请求时, 带上一个参数 requestName. 这里一开始的疑惑是, 当请求 a 带上参数 requestName 后, 发送多次请求, 判断 axios[requestName] 和 axios[requestName].cancel 存在时, 会做取消处理. 那发送成功后, 再点击时, axios[requestName] 和 axios[requestName].cancel 还是会存在啊. 这样还是会执行 axios[requestName].cancel(). 这里是因为当上一次请求发送成功后, 其 axios[requestName].cancel 这个方法已经失效, 即使执行了这个方法也不起作用. axios[requestName].cancel 的值永远是上一次的请求的取消回调. 当上一次请求成功后, 该回调会失效.
- axios.interceptors.request.use(config => {
- let requestName = config.data.requestName
- if (requestName) {
- if (axios[requestName] && axios[requestName].cancel) {
- axios[requestName].cancel()
- }
- config.cancelToken = new CancelToken (c => {
- axios[requestName] = {}
- axios[requestName].cancel = c
- })
- }
- return config
- }, error => {
- return Promise.reject(error)
- })
复制代码
响应的错误处理封装
- axios.interceptors.response.use(config => {
- Indicator.close()
- return config
- }, error => {
- cancelFlag = true
- Indicator.close()
- if (error && error.response) {
- switch (error.response.status) {
- case 400:
- error.message = '错误请求'
- break;
- case 401:
- error.message = '未授权, 请重新登录'
- break;
- case 403:
- error.message = '拒绝访问'
- break;
- case 404:
- error.message = '请求错误, 未找到该资源'
- break;
- case 405:
- error.message = '请求方法未允许'
- break;
- case 408:
- error.message = '请求超时'
- break;
- case 500:
- error.message = '服务器端出错'
- break;
- case 501:
- error.message = '网络未实现'
- break;
- case 502:
- error.message = '网络错误'
- break;
- case 503:
- error.message = '服务不可用'
- break;
- case 504:
- error.message = '网络超时'
- break;
- case 505:
- error.message = 'http 版本不支持该请求'
- break;
- default:
error.message = ` 连接错误 ${error.response.status}`
- }
- } else {
- error.message = "连接到服务器失败"
- }
- return Promise.reject(error.message)
- })
复制代码
http.js(封装了 post 和 get 请求)
在 axios.js 文件里对响应拦截器做了判断 error.response.status 的值的处理, 根据不同的状态码返回不同的 error 说明. 在 http.js 文件里 post 和 get 函数的参数为三个, 第三个参数 error 就是出现错误时的文案. 使用该 api 可以自己设置该文案, 如果不传这个参数, 那么就返回 axios.js 设置的 error 文案
- import Vue from 'vue'
- import axios from './axios'
- import 'mint-ui/lib/style.CSS';
- import {Toast} from 'mint-ui'
- Vue.component(Toast)
- export function post (url, data, error) {
- return new Promise((resolve, reject) => {
- axios.post(url, data).then(res => {
- resolve(res)
- }, err => {
- err = error ? error : err
- Toast({
- message: err,
- duration: 500
- })
- })
- })
- }
- export function get (url, data, error) {
- return new Promise((resolve, reject) => {
- axios.post(url, {
- data: data
- }).then(res => {
- resolve(res)
- }, err => {
- err = error ? error : err
- Toast({
- message: err,
- duration: 500
- })
- })
- })
- }
复制代码
使用
1) 在 main.js 引入文件
- import axios from '../utils/axios.js'
- import {post, get} from '../utils/http.js'
- Vue.prototype.$axios = axios
- Vue.prototype.$post = post
- Vue.prototype.$get = get
复制代码
2) 组件中使用
- this.$post('/api/saveInfo', {
- value: this.value
- }, '请求失败啦~~~').then(res => {
- // alert(res.data)
- })
复制代码
代码: github 地址链接 https://github.com/munan2/axios
来源: https://juejin.im/post/5b714a44f265da27ea319fcb