美文网首页
vue3 中 axios 封装

vue3 中 axios 封装

作者: Cherry丶小丸子 | 来源:发表于2022-12-05 16:26 被阅读0次
    axios.js
    /**
     * axios 封装
     * 请求拦截、响应拦截、错误统一处理
     */
    import axios from 'axios';
    import router from '@/router/index.js';
    // import store from '@/store/index';
    import webStorage from '@/utils/webStorage.js';
    import domMessage from '@/utils/messageOnce.js';
    const messageOnce = new domMessage();
    
    // element-plus 的 ElMessage、ElMessageBox 的消息提示组件,可根据自己的 ui 组件更改
    import { ElMessage, ElMessageBox } from 'element-plus';
    
    class HttpRequest {
        static axiosInstance;
    
        static init() {
            // 创建 axios 实例
            this.axiosInstance = axios.create();
            // 设置请求超时
            this.axiosInstance.defaults.timeout = 10000;
            // 表示跨域请求时是否需要使用凭证
            this.axiosInstance.defaults.withCredentials = true;
    
            // 环境的切换,`baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL
            /* if (process.env.NODE_ENV == 'development') {
                this.axiosInstance.defaults.baseURL = 'https://www.baidu.com';
            }else if (process.env.NODE_ENV == 'test') {
                this.axiosInstance.defaults.baseURL = 'https://www.tencent.com';
            }else if (process.env.NODE_ENV == 'production') {
                this.axiosInstance.defaults.baseURL = 'https://www.alibaba.com';
            } */
    
            // 设置 post 请求头    application/x-www-form-urlencoded;application/json;
            this.axiosInstance.defaults.headers.common['Authorization'] = 'AUTH_TOKEN';
            this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8;';
            this.axiosInstance.all = axios.all; // 设置 axios 并发请求
    
            // 初始化拦截器
            this.initInterceptors();
            return this.axiosInstance;
        }
    
        static initInterceptors() {
            // 添加请求拦截器
            this.axiosInstance.interceptors.request.use(
                config => {
                    // 在发送请求之前做些什么
    
                    /* 登录流程控制中,根据本地是否存在 token 判断用户的登录情况
                    但是即使 token 存在,也有可能 token 是过期的,所以在每次的请求头中携带 token
                    后台根据携带的 token 判断用户的登录情况,并返回给我们对应的状态码
                    而后我们可以在响应拦截器中,根据状态码进行一些统一的操作 */
                    webStorage.ls.get('token') && (config.headers.Authorization = `Bearer ${webStorage.ls.get('token')}`);
                    return config;
                },
                error => {
                    // 对请求错误做些什么
                    return Promise.reject(error);
                }
            );
    
            // 添加响应拦截器
            this.axiosInstance.interceptors.response.use(
                response => {
                    // 对响应数据做点什么
    
                    // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据,否则的话抛出错误
                    if (response.status === 200) {
                        return Promise.resolve(response);
                    } else {
                        return Promise.reject(response);
                    }
                    // return response;
                },
                error => {
                    // 服务器状态码不是 200 的情况
                    // 对响应错误做点什么
    
                    const { config, code, request, response, isAxiosError, toJSON } = error;
                    if (response) {
                        // 请求已发出,但是不在2xx的范围
                        this.errorHandle(response.status, response.data.message);
                        return Promise.reject(response);
                    } else {
                        // 超时提示
                        if (error.message.includes('timeout')) {
                            messageOnce.messageBox({
                                title: '提示',
                                message: '请求超时,请稍后重试',
                                lockScroll: true,
                                showCancelButton: false,
                                showConfirmButton: true,
                                cancelButtonText: '取消',
                                confirmButtonText: '确定',
                                cancelButtonClass: 'cancelBtn',
                                confirmButtonClass: 'sureBtn',
                                closeOnClickModal: false,
                                closeOnPressEscape: false
                            });
                            return Promise.reject(error);
                        }
    
                        /* 处理断网的情况
                        eg: 请求超时或断网时,更新 state 的 network 状态
                        network 状态在 app.vue 中控制着一个全局的断网提示组件的显示隐藏
                        关于断网组件中的刷新重新获取数据,会在断网组件中说明 */
                        if (!window.navigator.onLine) {
                            // 如果断网....
                            // store.commit('changeNetwork', false);
                        } else {
                            return Promise.reject(error);
                        }
                    }
                }
            );
        }
    
        /**
         * 请求失败后的错误统一处理
         * @param {Number} status 请求失败的状态码
         * 1**  信息,服务器收到请求,需要请求者继续执行操作
         * 2**  成功,操作被成功接收并处理
         * 3**  重定向,需要进一步的操作以完成请求
         * 4**  客户端错误,请求包含语法错误或无法完成请求
         * 5**  服务器错误,服务器在处理请求的过程中发生了错误
         */
        static errorHandle(status, other) {
            // 状态码判断
            switch (status) {
                // 400: 请求错误
                case 400:
                    messageOnce.messageBox({
                        title: '提示',
                        message: '请求错误',
                        confirmButtonClass: 'sureBtn'
                    });
                    break;
                // 401: 未登录状态,跳转登录页
                case 401:
                    messageOnce.messageBox({
                        title: '提示',
                        message: '登陆状态已过期,请重新登录',
                        confirmButtonClass: 'sureBtn',
                        callback: () => {
                            router.push({ name: 'login' });
                            webStorage.ls.clear();
                        }
                    });
                    break;
                // 403 权限不足,拒绝访问
                case 403:
                    messageOnce.messageBox({
                        title: '提示',
                        message: '权限不足,拒绝访问',
                        confirmButtonClass: 'sureBtn'
                    });
                    break;
                // 404 请求不存在
                case 404:
                    messageOnce.messageBox({
                        title: '提示',
                        message: '请求的资源不存在或请求地址出错',
                        confirmButtonClass: 'sureBtn'
                    });
                    break;
                // 服务器错误
                case 500:
                    messageOnce.messageBox({
                        title: '提示',
                        message: '服务器错误',
                        confirmButtonClass: 'sureBtn'
                    });
                    break;
                // 服务不可用
                case 503:
                    messageOnce.messageBox({
                        title: '提示',
                        message: '由于超载或系统维护,服务器暂无服务',
                        confirmButtonClass: 'sureBtn'
                    });
                    break;
                // token 异常
                case 1000001:
                    messageOnce.messageBox({
                        title: '提示',
                        message: 'token异常,请联系管理员',
                        confirmButtonClass: 'sureBtn'
                    });
                    break;
                default:
                    console.log(other);
            }
        }
    }
    
    export default HttpRequest.init();
    
    /**
     * 100  继续。客户端应继续其请求
     * 101  切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
     *
     * 200  请求成功。一般用于GET与POST请求
     * 201  已创建。成功请求并创建了新的资源
     * 202  已接受。已经接受请求,但未处理完成
     * 203  非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
     * 204  无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
     * 205  重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
     * 206  部分内容。服务器成功处理了部分GET请求
     *
     * 300  多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
     * 301  永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
     * 302  临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
     * 303  查看其它地址。与301类似。使用GET和POST请求查看
     * 304  未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
     * 305  使用代理。所请求的资源必须通过代理访问
     * 306  已经被废弃的HTTP状态码
     * 307  临时重定向。与302类似。使用GET请求重定向
     *
     * 400  客户端请求的语法错误,服务器无法理解
     * 401  请求要求用户的身份认证
     * 402  保留,将来使用
     * 403  服务器理解请求客户端的请求,但是拒绝执行此请求
     * 404  服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
     * 405  客户端请求中的方法被禁止
     * 406  服务器无法根据客户端请求的内容特性完成请求
     * 407  请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
     * 408  服务器等待客户端发送的请求时间过长,超时
     * 409  服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
     * 410  客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
     * 411  服务器无法处理客户端发送的不带Content-Length的请求信息
     * 412  客户端请求信息的先决条件错误
     * 413  由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
     * 414  请求的URI过长(URI通常为网址),服务器无法处理
     * 415  服务器无法处理请求附带的媒体格式
     * 416  客户端请求的范围无效
     * 417  服务器无法满足Expect的请求头信息
     *
     * 500  服务器内部错误,无法完成请求
     * 501  服务器不支持请求的功能,无法完成请求
     * 502  作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
     * 503  由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
     * 504  充当网关或代理的服务器,未及时从远端服务器获取请求
     * 505  服务器不支持请求的HTTP协议的版本,无法完成处理
     */
    
    webStorage.js
    // webStorage.js
    
    import Storage from 'vue-ls';
    const localStorageOptions = {
        namespace: 'vue-', // key prefix
        name: 'ls', // name variable Vue.[ls] or this.[$ls],
        storage: 'local' // storage name session, local, memory
    };
    const sessionStorageOptions = {
        namespace: 'vue-', // key prefix
        name: 'ss', // name variable Vue.[ls] or this.[$ls],
        storage: 'session' // storage name session, local, memory
    };
    
    export default {
        ls: Storage.useStorage(localStorageOptions).ls,
        ss: Storage.useStorage(sessionStorageOptions).ls
    };
    
    messageOnce.js
    // messageOnce.js
    import { ElMessage, ElMessageBox } from 'element-plus';
    
    const showMessage = Symbol('showMessage');
    const showMessageBox = Symbol('showMessageBox');
    
    export default class domMessage {
        // Message
        message(options, single = true) {
            this[showMessage](options, single);
        }
        [showMessage](options, single) {
            if (single) {
                // 判断当前页是否有 el-message 标签,如果没有则执行消息提示操作
                if (document.getElementsByClassName('el-message').length === 0) {
                    ElMessage(options);
                }
            } else {
                ElMessage(options);
            }
        }
    
        // MessageBox
        messageBox(options, single = true) {
            this[showMessageBox](options, single);
        }
        [showMessageBox](options, single) {
            if (single) {
                // 判断当前页是否有 el-message-box 标签,如果没有则执行消息提示操作
                if (
                    document.getElementsByClassName('el-message-box').length === 0 ||
                    document.getElementsByClassName('el-overlay')[0].style.display === 'none'
                ) {
                    ElMessageBox(options).then(() => {});
                }
            } else {
                ElMessageBox(options).then(() => {});
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:vue3 中 axios 封装

          本文链接:https://www.haomeiwen.com/subject/gokifdtx.html