Vue3+Axios网络请求封装

这篇具有很好参考价值的文章主要介绍了Vue3+Axios网络请求封装。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文将详细介绍一款基于Axios+Typescript封装的网络请求库,该库可以自动携带token、拦截请求和响应等操作,并能够处理请求重复、超时和错误状态码等异常情况。

介绍

Axios是基于Node.js的HTTP客户端,也是一款广泛使用的网络请求库。它具有使用简单、可扩展性高、易用性好等特点,因此成为大多数前端开发者的首选,从而衍生了很多基于axios封装的网络请求库。

今天我们要介绍的网络请求库是基于axios封装的,命名为Axios,它实现了自动携带token、拦截请求和响应等操作,能够处理请求重复、超时和错误状态码等异常情况。

代码说明

代码主要分为以下几个部分:

  1. import导入模块。在这个代码段中,我们导入了axioselement-plus两个模块,并对其进行了解构。
  2. 定义两个接口,CustomOptionsLoadingOptions。分别用于定义自定义配置和加载选项的接口,方便在调用Axios方法时传递配置和选项。
  3. 定义了一个Map对象pendingMap,用于储存每个请求的唯一回调函数。
  4. 定义了一个LoadingInstance对象,用于储存loading实例和计数器。
  5. getTokenAUTH()方法用于获取token,该方法可以根据实际情况编写。
  6. Axios()方法是Axios库的核心方法,主要进行了请求和响应拦截,并处理了请求重复、超时和错误状态码等异常情况。
  7. httpErrorStatusHandle()方法用于处理错误状态码。
  8. closeLoading()方法用于关闭loading层实例。
  9. addPending()方法用于储存每个请求的唯一回调函数,以此为标识。
  10. removePending()方法用于删除重复请求。
  11. getPendingKey()方法用于生成每个请求的唯一key。

结论

Axios封装的网络请求库,能够大大简化前端开发的工作,提高开发效率。本文介绍了该库的详细内容,希望对读者有所帮助。如果还有什么疑问或建议,欢迎在下方留言。

完整代码(中间件/网络请求拦截器-Typescript版本)

import axios, {AxiosRequestConfig, AxiosError, AxiosResponse, CancelToken} from 'axios';
import {ElLoading, ElMessage} from 'element-plus';

interface CustomOptions {
    repeat_request_cancel?: boolean;
    loading?: boolean;
    restore_data_format?: boolean;
    error_message_show?: boolean;
    code_message_show?: boolean;
}

interface LoadingOptions {
    fullscreen?: boolean;
    text?: string;
    customClass?: string;
    spinner?: string;
    background?: string;
}

const pendingMap: Map<string, CancelToken> = new Map();

interface LoadingInstance {
    _target: any;
    _count: number;
}

const LoadingInstance: LoadingInstance = {
    _target: null,
    _count: 0,
};

function getTokenAUTH(): string {
    return "";
}

function Axios(
    axiosConfig: AxiosRequestConfig,
    customOptions: CustomOptions = {},
    loadingOptions: LoadingOptions = {}
) {
    const service = axios.create({
        baseURL: process.env.VUE_APP_BASE_API,
        timeout: 1000 * 60,
        responseType: 'json',
    });

    // 自定义配置
    const custom_options = Object.assign(
        {
            repeat_request_cancel: true,
            loading: false,
            restore_data_format: true,
            error_message_show: true,
            code_message_show: false,
        },
        customOptions
    );

    // 请求拦截
    service.interceptors.request.use(
        (config: any) => {
            removePending(config);
            custom_options.repeat_request_cancel && addPending(config);
            // 创建loading实例
            if (custom_options.loading) {
                LoadingInstance._count++;
                if (LoadingInstance._count === 1) {
                    LoadingInstance._target = ElLoading.service(loadingOptions);
                }
            }
            // 自动携带token
            if (getTokenAUTH() && typeof window !== 'undefined') {
                config.headers.Authorization = getTokenAUTH() as string;
            }

            return config;
        },
        (error: AxiosError) => {
            return Promise.reject(error);
        }
    );

    // 响应拦截
    service.interceptors.response.use(
        (response: AxiosResponse) => {
            removePending(response.config);
            custom_options.loading && closeLoading(custom_options); // 关闭loading
            if (
                custom_options.code_message_show &&
                response.data &&
                response.data.code !== 200
            ) {
                ElMessage({
                    type: 'error',
                    message: response.data.msg as string,
                });
                return Promise.reject(response.data); // code不等于200, 页面具体逻辑就不执行了
            }

            return custom_options.restore_data_format
                ? response.data
                : response;
        },
        (error: AxiosError) => {
            error.config && removePending(error.config);
            custom_options.loading && closeLoading(custom_options); // 关闭loading
            custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码
            return Promise.reject(error); // 错误继续返回给到具体页面
        }
    );

    return service(axiosConfig);
}

export default Axios;

/**
 * 处理异常
 * @param {*} error
 */
function httpErrorStatusHandle(error: any) {
    // 处理被取消的请求
    if (axios.isCancel(error)) return console.error('请求的重复请求:' + error.message);
    let message = '';
    if (error && error.response) {
        switch (error.response.status) {
            case 302:
                message = '接口重定向了!';
                break;
            case 400:
                message = '参数不正确!';
                break;
            case 401:
                message = '您未登录,或者登录已经超时,请先登录!';
                break;
            case 403:
                message = '您没有权限操作!';
                break;
            case 404:
                message = `请求地址出错: ${error.response.config.url}`;
                break; // 在正确域名下
            case 408:
                message = '请求超时!';
                break;
            case 409:
                message = '系统已存在相同数据!';
                break;
            case 500:
                message = '服务器内部错误!';
                break;
            case 501:
                message = '服务未实现!';
                break;
            case 502:
                message = '网关错误!';
                break;
            case 503:
                message = '服务不可用!';
                break;
            case 504:
                message = '服务暂时无法访问,请稍后再试!';
                break;
            case 505:
                message = 'HTTP版本不受支持!';
                break;
            default:
                message = '异常问题,请联系管理员!';
                break;
        }
    }
    if (error.message.includes('timeout')) message = '网络请求超时!';
    if (error.message.includes('Network'))
        message = window.navigator.onLine ? '服务端异常!' : '您断网了!';

    ElMessage({
        type: 'error',
        message,
    });
}

/**
 * 关闭Loading层实例
 * @param {*} _options
 */
function closeLoading(_options: CustomOptions) {
    if (_options.loading && LoadingInstance._count > 0)
        LoadingInstance._count--;
    if (LoadingInstance._count === 0) {
        LoadingInstance._target.close();
        LoadingInstance._target = null;
    }
}

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 * @param {*} config
 */
function addPending(config: AxiosRequestConfig) {
    const pendingKey = getPendingKey(config);
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel: any) => {
        if (!pendingMap.has(pendingKey)) {
            pendingMap.set(pendingKey, cancel);
        }
    });
}

/**
 * 删除重复的请求
 * @param {*} config
 */
function removePending(config: AxiosRequestConfig) {
    const pendingKey = getPendingKey(config);
    if (pendingMap.has(pendingKey)) {
        const cancelToken: any = pendingMap.get(pendingKey);
        cancelToken(pendingKey);
        pendingMap.delete(pendingKey);
    }
}

/**
 * 生成唯一的每个请求的唯一key
 * @param {*} config
 * @returns
 */
function getPendingKey(config: AxiosRequestConfig) {
    const info: AxiosRequestConfig = config;
    if (typeof info.data === 'string') info.data = JSON.parse(info.data); // response里面返回的config.data是个字符串对象
    return [info.url, info.method, JSON.stringify(info.params), JSON.stringify(info.data)].join('&');
}

使用(Typescript版本)

import request from "@/utils/Request";

/**
 *    获取专题
 */
export const GetSpecial = (data: object) => request({
    url: '/list',
    method: 'GET',
    params: data
});

完整代码(中间件/网络请求拦截器-Js版本)

import axios from 'axios';
import {ElLoading, ElMessage} from 'element-plus';

const pendingMap = new Map();

const LoadingInstance = {
    _target: null,
    _count: 0
};

function getTokenAUTH() {
    return null
}

function Axios(axiosConfig, customOptions, loadingOptions) {
    const service = axios.create({
        baseURL: process.env.VUE_APP_BASE_API,
        timeout: 1000 * 60,
        responseType: 'json'
    });

    // 自定义配置
    let custom_options = Object.assign({
        repeat_request_cancel: true, // 是否开启取消重复请求, 默认为 true
        loading: false, // 是否开启loading层效果, 默认为false
        restore_data_format: true, // 是否开启简洁的数据结构响应, 默认为true
        error_message_show: true, // 是否开启接口错误信息展示,默认为true
        code_message_show: true, // 是否开启code不为0时的信息提示, 默认为false
    }, customOptions);

    // 请求拦截
    service.interceptors.request.use(
        config => {
            removePending(config);
            custom_options.repeat_request_cancel && addPending(config);
            // 创建loading实例
            if (custom_options.loading) {
                LoadingInstance._count++;
                if (LoadingInstance._count === 1) {
                    LoadingInstance._target = ElLoading.service(loadingOptions);
                }
            }
            // 自动携带token
            if (getTokenAUTH() && typeof window !== "undefined") {
                config.headers.Authorization = getTokenAUTH();
            }

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

    // 响应拦截
    service.interceptors.response.use(
        response => {
            removePending(response.config);
            custom_options.loading && closeLoading(custom_options); // 关闭loading
            if (custom_options.code_message_show && response.data && response.data.code !== 200) {
                ElMessage({
                    type: 'error',
                    message: response.data.msg
                })
                return Promise.reject(response.data); // code不等于200, 页面具体逻辑就不执行了
            }

            return custom_options.restore_data_format ? response.data : response;
        },
        error => {
            error.config && removePending(error.config);
            custom_options.loading && closeLoading(custom_options); // 关闭loading
            custom_options.error_message_show && httpErrorStatusHandle(error); // 处理错误状态码
            return Promise.reject(error); // 错误继续返回给到具体页面
        }
    );

    return service(axiosConfig)
}

export default Axios;

/**
 * 处理异常
 * @param {*} error
 */
function httpErrorStatusHandle(error) {
    // 处理被取消的请求
    if (axios.isCancel(error)) return console.error('请求的重复请求:' + error.message);
    let message = '';
    if (error && error.response) {
        switch (error.response.status) {
            case 302:
                message = '接口重定向了!';
                break;
            case 400:
                message = '参数不正确!';
                break;
            case 401:
                message = '您未登录,或者登录已经超时,请先登录!';
                break;
            case 403:
                message = '您没有权限操作!';
                break;
            case 404:
                message = `请求地址出错: ${error.response.config.url}`;
                break; // 在正确域名下
            case 408:
                message = '请求超时!';
                break;
            case 409:
                message = '系统已存在相同数据!';
                break;
            case 500:
                message = '服务器内部错误!';
                break;
            case 501:
                message = '服务未实现!';
                break;
            case 502:
                message = '网关错误!';
                break;
            case 503:
                message = '服务不可用!';
                break;
            case 504:
                message = '服务暂时无法访问,请稍后再试!';
                break;
            case 505:
                message = 'HTTP版本不受支持!';
                break;
            default:
                message = '异常问题,请联系管理员!';
                break
        }
    }
    if (error.message.includes('timeout')) message = '网络请求超时!';
    if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常!' : '您断网了!';

    ElMessage({
        type: 'error',
        message
    })
}

/**
 * 关闭Loading层实例
 * @param {*} _options
 */
function closeLoading(_options) {
    if (_options.loading && LoadingInstance._count > 0) LoadingInstance._count--;
    if (LoadingInstance._count === 0) {
        LoadingInstance._target.close();
        LoadingInstance._target = null;
    }
}

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 * @param {*} config
 */
function addPending(config) {
    const pendingKey = getPendingKey(config);
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
        if (!pendingMap.has(pendingKey)) {
            pendingMap.set(pendingKey, cancel);
        }
    });
}


/**
 * 删除重复的请求
 * @param {*} config
 */
function removePending(config) {
    const pendingKey = getPendingKey(config);
    if (pendingMap.has(pendingKey)) {
        const cancelToken = pendingMap.get(pendingKey);
        cancelToken(pendingKey);
        pendingMap.delete(pendingKey);
    }
}

/**
 * 生成唯一的每个请求的唯一key
 * @param {*} config
 * @returns
 */
function getPendingKey(config) {
    let {url, method, params, data} = config;
    if (typeof data === 'string') data = JSON.parse(data); // response里面返回的config.data是个字符串对象
    return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&');
}

使用(Js版本)

import request from "@/utils/Request";

/**
 *    获取专题
 */
export let GetSpecial = (data) => request({
    url: '/list',
    method: 'GET',
    params: data
});

完结~文章来源地址https://www.toymoban.com/news/detail-468512.html

到了这里,关于Vue3+Axios网络请求封装的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3 网络请求——axios 高级用法之 axios 拦截器实战与并发请求

    Axios 是一个流行的基于 Promise 的 HTTP 客户端库,用于在浏览器和 Node.js 中发出 HTTP 请求。 Axios 还支持请求和响应的拦截器。接下来通过这篇文章,我们一起来学习和了解一下 Axios 拦截器和并发请求,通过实际代码来介绍如何使用 Axios 拦截器。 拦截器会在发生响应请求之前和

    2024年02月10日
    浏览(45)
  • Vue项目的网络请求代理到封装详细步骤

    1.创建vue项目 demo是项目名称 2.安装axios  进入demo里面打开终端(黑窗口),执行 3.进行config.js配置 4.main.js里引入 5.src目录下新建Utils文件夹,在内封装request.js 6.以login路由为示例  src文件下新建api文件,在api内新建login.js 7.在页面内引入方法,并使用 简单明了

    2023年04月27日
    浏览(51)
  • 【axios网络请求库】认识Axios库;axios发送请求、创建实例、创建拦截器、封装请求

    功能特点: 在浏览器中发送 XMLHttpRequests 请求 在 node.js 中发送 http请求 支持 Promise API 拦截请求和响应 转换请求和响应数据 支持多种请求方式: axios(config) axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, c

    2024年02月10日
    浏览(43)
  • axios封装—vue3项目

    前言 axios的API很友好,可以在项目中直接使用。但是在大型项目中,http请求很多,且需要区分环境, 每个网络请求有相似需要处理的部分,会导致代码冗余,破坏工程的可维护性,扩展性,所以需要对axios请求进行相应的封装 正文 安装axios 封装请求api 1. 在src目录下新建个

    2024年02月07日
    浏览(78)
  • vue3中axios整体封装

    在 vue3.x 版本中进行封装 使用 promise 封装 post 和 get 方法 api 作为单独模块维护 适配 vue.config.js 中 proxy 代理 结合 async 和 await 1 安装 2 创建http模块 在 src 目录下,创建 request 文件夹,并在该文件夹下,新建 http.js 文件 3 创建单独的api模块 4 在业务代码中使用 5 在vue.config.js中配

    2024年02月17日
    浏览(47)
  • vue2使用axios封装请求数据,教会你封装,简单易懂,轻松学会axios封装请求数据 看一眼就会 手把手教会

    2、完成上面的步骤还不够,还需要再创建一个文件夹api,然后在文件夹里面创建自定义的文件名(我创建的是cartApi.js)文件名根据自己的需求命名 下面就是根据自己的请求接口以及数据参数请求,下面的请求是一些常见的post、get请求以及传参啥的(仅供参考,可以参考下面

    2024年01月24日
    浏览(57)
  • html+Vue+封装axios实现发送请求

    在html中使用Vue和Axios时,可以在HTML中引入Vue库和Axios库,然后使用Vue的语法和指令来创建Vue组件和模板。在Vue组件中,你可以使用Axios发送HTTP请求来获取数据,并将数据绑定到Vue模板中进行展示。 这段代码在HTML中使用了Vue,使用axios并设置了请求拦截器和响应拦截器。它实现

    2024年02月13日
    浏览(53)
  • 前端vue2中axios封装请求数据,教会你封装教会你请求数据 简单易懂,轻松学会axios封装请求数据 看一眼就会 手把手教会

    2、完成上面的步骤还不够,还需要再创建一个文件夹api,然后在文件夹里面创建自定义的文件名(我创建的是cartApi.js)文件名根据自己的需求命名 下面就是根据自己的请求接口以及数据参数请求,下面的请求是一些常见的post、get请求以及传参啥的(仅供参考,可以参考下面

    2024年02月03日
    浏览(50)
  • vue中axios的二次封装——vue 封装axios详细步骤

        api统一管理,不管接口有多少,所有的接口都可以非常清晰,容易维护。     通常我们的项目会越做越大,页面也会越来越多,如果页面非常的少,直接用axios也没有什么大的影响,那页面组件多了起来,上百个接口呢,这个时候后端改了接口,多加了一个参数什么的呢

    2024年02月02日
    浏览(54)
  • Vue3创建项目(四)axios封装及接口配置

    项目结构:  目录  🍉🍉🍉index.ts  🍉🍉🍉 api.ts 看完需要预计花费10分钟。 请求拦截器与响应拦截器  阅读下面代码需先了解以下内容:         请求拦截器:     请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,每次请求携带token传给

    2024年02月03日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包