Axios 网络请求库二次封装学习

发布于 2022-11-28 19:56:56 字数 6373 浏览 136 评论 0

封装的必要性

我们在使用 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 私有化,但是这样的方式会导致占有大量内存。
参考同事写的代码(版本二),我觉得非常的有道理。而且比较简单。

版本一、使用 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)
})
axios.interceptors.response.use(config => {
    cancelFlag = true
    Indicator.close()
    return config
}, 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
            })
        })
    })
}

使用

在 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

组件中使用

this.$post('/api/saveInfo', {
    value: this.value,
    requestName: 'name01'
}, '请求失败啦~~~').then(res => {
    // alert(res.data)
})

代码:github 地址链接

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文