首页 > 其他分享 >前端应该如何封装高扩展的axios请求库

前端应该如何封装高扩展的axios请求库

时间:2023-11-17 16:25:09浏览次数:24  
标签:axios return data 前端 interceptors 封装 config response

我看了很多 axios 的封装,但是我感觉他们的封装。也不够自由,主要是写完之后,如果以后有东西需要修改的时候,还要回去拦截器进行修改。但是有一些东西拦截器可能是你以后的业务需求才需要添加的。

我就在想我能不能拦截器做成插件式的模式进行动态配置呢?例如下面的效果,点击添加一个请求缓存器,请求的时候就读缓存。当然你也可以去掉直接到达效果。

实现这个功能我这需要下面的做法,就可以实现动态控制我们的 axios 来扩展请求业务。

this.interceptors.push(new xxxInterceptors());

动画.gif

如何进行考虑设计

首先为了让我们的系统拥有扩展性,我这里会先定义一个 IRequest interface,为以后要做的事情进行约束。我们平时使用 request 用的比较多就是只有 4 大请求方法。定义好接口之后,就是我们的实现方式了。

截屏2022-01-27 下午11.44.21.png

这样我们就可以把我们 node.js、fetch、小程序的 request 都实现然后给到系统调用层调用,他们不需要知道怎么实现,他们只需要知道我用什么类型的 Request 就 new 那个对象来进行使用即可。

在这个过程中,我们需要对 axios 进行重复请求处理。这个时候我需要一个 cache 来进行缓存。这一类的文章多得是,我和他们的做法不一样在于,我是使用 ES6 的 Map 做的 key,value 存储。我坚持使用 oop 去实现。React 除了视图使用 FC 模式去编写,处理业务的地方我还是推荐使用 oop 模式编码。

class AxiosHttpClient {
    private okHttp: AxiosInstance;
    private CancelToken = axios.CancelToken;
    private EXPIRE_TIME = 60000;

    private cache: Map<string | undefined, any> = new Map();

    public constructor() {
        this.okHttp = axios.create({ timeout: 10000, responseType: 'json' })

        this.okHttp.interceptors.request.use(config => {
            config = this.handleRequestCacheDoCacen(config);
            return config;
        })

        this.okHttp.interceptors.response.use(
            response => {
                response = this.handleResonseCacheDoCacen(response);
                return response;
            },
            err => {
                //已经取消的请求,我们需要把message 调到 response resolve里面进行正常的调用
                if (axios.isCancel(err)) {
                    return Promise.resolve(err.message);
                }
                return Promise.reject(err);
            }
        )
    }

    /**
     * 是否存在cache,如果存在取消请求
     */
    public handleRequestCacheDoCacen(config: AxiosRequestConfig<any>) {
        let source = this.CancelToken.source();
        config.cancelToken = source.token;
        let data = this.cache.get(config.url);
        if (data && GetTimeNowUnxi() - data.expire < this.EXPIRE_TIME) {
            source.cancel(data);
        }
        return config;
    }

     /**
     * 从缓存中获取Cache Data
     * @param response
     * @returns
     */
    public handleResonseCacheDoCacen(response: AxiosResponse<any>) {
        let data = {
            expire: GetTimeNowUnxi(),
            data: response.data
        };
        this.cache.set(`${response.config.url}`, data)
        return response;
    }

    public getHttpClient() {
        return this.okHttp;
    }

}

但是我写完后,发现interceptors就无法继续扩展了。如果后续需要维护我还得可能还要来这里进行修改。或者写以下 if 开关来处理逻辑。

这个时候你有很多种做法,用一个 Object/Array 来管理你的要做事情的handle,在interceptors里面进行for in / for of操作,这种做法类似与 pipe 流水线操作。不过我是偏向使用 rxjs 来做这种事情,但是前端按着发展速度,我不知道什么时候才有人意识到 rxjs。了解了 rxjs 后你会发现你那些vuex,dva,mobx等都是啥玩意。

为了照顾大多数前端,我这边设计使用的是观察者模式来实现interceptors热插槽处理。于是就有以下操作。

// index.js
class AxiosHttpClient {
    private okHttp: AxiosInstance;
    private CancelToken = axios.CancelToken;
    private $interceptorSubject: InterceptorSubject;

    private cache: Map<string | undefined, any> = new Map();
    private interceptors: Observer[] = []

    private static instance: AxiosHttpClient;
    public static getInstance() {
        if (!this.instance) {
            this.instance = new AxiosHttpClient();
        }
        return this.instance;
    }

    public constructor() {
        this.$interceptorSubject = new AxiosInterceptorSubject();
        this.okHttp = axios.create({ timeout: 10000, responseType: 'json' })
    }

    public getHttpClient() {

        this.okHttp.interceptors.request.use(config => {
            if (this.interceptors.length > 0) {
                for (let interceptor of this.interceptors) {
                    this.$interceptorSubject.attach(interceptor);
                }
                config = this.$interceptorSubject.notifyRequest(config);
            }

            return config;
        })

        this.okHttp.interceptors.response.use(
            response => {
                console.log(this.interceptors);
                if (this.interceptors.length > 0) {
                    response = this.$interceptorSubject.notifyResponse(response);
                }
                return response;
            },
            err => {
                //已经取消的请求,我们需要把message 调到 response resolve里面进行正常的调用
                if (axios.isCancel(err)) {
                    return Promise.resolve(err.message);
                }
                return Promise.reject(err);
            }
        )

        return this.okHttp;
    }

    public setCache(key: string, value: any) {
        this.cache.set(key, value);
    }

    public getCache(key: string | undefined) {
        return this.cache.get(key);
    }

    public getCancelToken() {
        return this.CancelToken;
    }

    public setInterceptorsObserver(ob: Observer) {
        this.interceptors.push(ob);
    }

    public removeInterceptorSubject(ob: Observer) {
        this.$interceptorSubject.detach(ob);
        const observerIndex = this.interceptors.indexOf(ob);
        this.interceptors.splice(observerIndex, 1);
    }

}

接口的定义

export interface InterceptorSubject {
  attach(observer: Observer): void;

  detach(observer: Observer): void;

  notifyRequest(config: AxiosRequestConfig): any;

  notifyResponse(response: AxiosResponse): any;
}

export interface Observer {
  update(config: AxiosRequestConfig): any;
  doResponse(config: AxiosResponse): any;
}

具体的实现类

import { AxiosRequestConfig, AxiosResponse } from 'axios';
import { AxiosHttpClient, EXPIRE_TIME } from 'core/request/unitys/axios';
import { GetTimeNowUnxi } from 'core/time';
import { Observer } from './InterceptorSubject';


export class AxiosCacheInterceptor implements Observer {
    private app = AxiosHttpClient.getInstance();

    update(config: AxiosRequestConfig): any {
        let source = this.app.getCancelToken().source();
        config.cancelToken = source.token;
        let data = this.app.getCache(config.url);
        if (data && GetTimeNowUnxi() - data.expire < EXPIRE_TIME) {
            source.cancel(data);
        }
        return config;
    }

    doResponse(response: AxiosResponse<any, any>) {
        let data = {
            expire: GetTimeNowUnxi(),
            data: response.data
        };
        this.app.setCache(`${response.config.url}`, data)
        return response;
    }
}

然后再 App 的 main.ts 入口文件,把我需要的业务代码都注入到Subject里面进行调用监听。

image.png

我们现在就可以通过业务来动态控制我们的 axios 了...

标签:axios,return,data,前端,interceptors,封装,config,response
From: https://www.cnblogs.com/wp-leonard/p/17839024.html

相关文章

  • axios、ajax、fetch三者的区别
    1.ajax:是指一种创建交互式网页应用的网页开发技术,并且可以做到无需重新加载整个网页的情况下,能够更新部分网页,也叫作局部更新优缺点:1)局部更新2)原生支持,不需要任何插件3)原生支持,不需要任何插件4)可能破坏浏览器后退功能5)嵌套回调,难以处理2.axios:是一个基于promise的HTTP......
  • axios请求失败、请求超时重新发送请求
    一、axios重新发送请求基础版(所有的请求错误,不论是请求超时还是接口请求出错都会进行重试)以下是一个完整的文件,看懂了的话axios重试请求也就基本会了,不会的话直接复制到项目里,也可以直接调用使用。创建一个axios实例,并在实例中设置请求超时时间timeout、重试请求次数re......
  • axios请求并发限制
    队列有x个之后执行正文在网上看到这么一道题:首先来实现一个分割数组的函数~constgroup=(list=[],max=0)=>{if(!list.length){returnlist;}letresults=[];for(leti=0,len=list.length;i<len;i+=max){results.push(list.s......
  • 42.封装
    访问控制在Python中并没有像Java,C++一样,提供了 public, protected, private 这样的访问控制修饰符,Python通过一种称为 名称改写的方式,实现其它语言中访问控制修饰符的作用。但是要注意的是,在Python中名称改写只是一种约定,并没有真正的实现私有的作用,在Python中只要想......
  • 在线CAD SDK前端库绘制规则多边形图形
    前言在CAD(计算机辅助设计)领域,绘制多边形是常见的任务之一。MxCAD是一款专注在线CAD的前端库,提供了丰富的绘图和设计功能,使得绘制多边形变得轻松而灵活。本文将带领您通过使用MxCAD实现绘制多边形的过程,深入了解其基本概念和功能。mxcad 是一个基于TypeScript的前端库,专为......
  • 前端大文件上传如何做到刷新续传?
    前言这两天在学习阿里云oss上传。踩了不少坑,终于实现了大文件分片、断点续传的功能。这篇文章主要分享学习笔记,希望能给大家一些帮助。先看效果 技术栈1.前端:react+Ts+axios上传文件2.Node部分:定义接口、阿里云oss3.socket.io:实时同步上传进度特别说明axios中onUploadPr......
  • 前端如何实现大文件上传
    在开发过程中,经常会遇到一些较大文件上传,如果只使用一次请求去上传文件,一旦这次请求中出现什么问题,那么无论这次上传了多少文件,都会失去效果,用户则需要重新上传所有资源。所以就想到一种方式,将一个大文件分成多个小文件,这样通过多个请求实现大文件上传。接下来我们就来看看具体是怎......
  • AO3400-ASEMI中低压MOS管AO3400参数、封装、尺寸
    编辑:llAO3400-ASEMI中低压MOS管AO3400参数、封装、尺寸型号:AO3400品牌:ASEMI封装:SOT-23连续漏极电流(Id):5.8A漏源电压(Vdss):30V功率(Pd):1.4W芯片个数:1引脚数量:3类型:MOS管特性:N沟道MOS管、中低压MOS管RDS(on):28mΩVGS:1.45封装尺寸:如图工作温度:-55°C~150°CAO3400......
  • 全栈工程师必须要掌握的前端Html技能
    作为一名全栈工程师,在日常的工作中,可能更侧重于后端开发,如:C#,Java,SQL,Python等,对前端的知识则不太精通。在一些比较完善的公司或者项目中,一般会搭配前端工程师,UI工程师等,来弥补后端开发的一些前端经验技能上的不足。但并非所有的项目都会有专职前端工程师,在一些小型项目或者初创公......
  • springboot整合前端实现断点续传、大文件秒传以及多线程上传下载
    前端,百度开源框架webuploader新建upload.htmlwebuploader官网地址:http://fex.baidu.com/webuploader/<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>webuploader</title></head><!--引......