Typescript封装框架(一) 网络请求篇

如何封装网络请求框架

年末的时候用了typescript做新项目,还是学到很多,记录一下,学了之后,先是学了下如何将Axios改成Typescript版本的,Typescript在我的理解是加了类型的限制,八月份面试的时候,有个人问我,ts和js有什么不同?

大概是强类型更加规范,对面向对象支持比较好.因为大学学的是JAVA搞过几年安卓,所以对面向对象的语言很有好感,到现在我还是觉得JAVA很规范,我是不是对不住web前端?我是真在安卓上学到很多.

当然对ts,到现在我也不能讲出一朵花,一直写业务,说实话,没时间去反思.个人还没什么深刻的理解,不过会带着这个问题去学习.

正题,不废话.

单例模式创建AXIOS实例

一般来说,基本地址是固定的,全局使用,就需要用单例,只让其分配一次,单例有懒饿汉,做前端很少涉及线程的,所以就不用考虑加锁保持变量只被一个线程访问之类,除非业务有需求,例如:支付业务平台和普通业务平台是分开的

static关键字不能少,static优先于对象存在,可通过类名直接访问,因为this指向是实例,所以这里不能用this访问,如果不加上static,则实例不是全局的,每一次请求都会生成,而设置为static类全局变量,随着类加载去产生,只会生成一次.私有化,只有类本身才能改变其值.

如何深入理解static关键字,研究js的内存管理之后去说

class NetWorkUtils {
  private static instance: AxiosInstance | null = null;
    constructor() {
    if (NetWorkUtils.instance === null) {
        NetWorkUtils.instance = axios.create({
              baseURL: process.env.VUE_APP_URL,
              timeout: 50000, // request timeout
            });
       }
        //TODO 
        //可配置下请求拦截器
   }
}

针对多个平台基地址不同,baseURL作为参数,导出对象供使用,仍然能保持全局唯一,去掉static关键字

export const NetWorkUtil = new NetWorkUtils(process.env.VUE_APP_URL);
export const NetWorkPayUtil = new NetWorkUtils(process.env.VUE_APP_PAY_URL);

响应父实体类

响应数据的格式往往统一,data里面的类型多种形态,用泛型代替,到时候反射为原类型

export default interface BaseResponse<T = any> {
  code: string;
  data: T;
  msg: string;
}

声明类型准备上

declare type Methods =
  | 'get'
  | 'GET'
  | 'delete'
  | 'DELETE'
  | 'head'
  | 'HEAD'
  | 'options'
  | 'OPTIONS'
  | 'post'
  | 'POST'
  | 'put'
  | 'PUT'
  | 'patch'
  | 'PATCH';

规定返回类型为AxiosPromise

import axios, {
  AxiosInstance,
  AxiosPromise,
  AxiosRequestConfig,
  AxiosResponse,
} from 'axios';

axios.defaults.withCredentials = true;

//后端不支持RESTful接口,如果支持还可以使用Record定义每个方法,然后去实现
declare type Methods =
  | 'get'
  | 'GET'
  | 'post'
  | 'POST'

/**
 * transformRequest 函数数组
 */
interface Config {
  data?: any;
  params?: any;
  url?: string;
  headers?: any;
  responseType?: string;
  transformRequest?: Array<any>;
}

class NetWorkUtils {
  private instance: AxiosInstance | null = null;

  constructor(url:string) {
    if (this.instance === null) {
      this.instance = axios.create({
          baseURL: url,
          timeout: 5000, // request timeout
        });
      this.initInterceptors();
    }
  }

  /**
   * 初始化请求响应的拦截器
   */
  private initInterceptors(): void {
    this.instance!.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        const sid = window.localStorage.getItem('sessionId');
        if (sid) {
          Object.assign(config.headers, { sessionId: sid });
        }
        return config;
      },
      error => {
        Promise.reject(error);
      }
    );

    this.instance!.interceptors.response.use(
      (response: AxiosResponse) => {
        return response;
      },
      error => {
        return error;
      }
    );
  }
  /**
   * @param {string} url 请求连接
   * @param {string} method HTTP方式
   * @param {any} data 数据
   * @returns {Promise} 返回的异步
   */
  createAPI<T,R>(url: string, method: Methods, data?: T): AxiosPromise<R> {
    const config: Config = {};
    if (method === 'get' || method === 'GET') {
      config.params = data;
    } else {
      config.data = data;
    }
    return this.instance!(Object.assign(config, { method, url }));
  }

  createFormAPI<T>(
    url: string,
    method: Methods,
    data?: T,
    responseType?: string
  ): AxiosPromise {
    if (!responseType) {
      responseType = 'json';
    }
    const config: Config = {
      data: data,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      responseType,
      transformRequest: [],
    };
    config.transformRequest = [
      function(data: { [x: string]: string | number | boolean }) {
        let ret = '';
        for (const key in data) {
          ret += `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}&`;
        }
        return ret;
      },
    ];
    return this.instance!(Object.assign(config, { method, url }));
  }
}

export const NetWorkUtil = new NetWorkUtils(process.env.VUE_APP_URL);
export const NetWorkPayUtil = new NetWorkUtils(process.env.VUE_APP_PAY_URL);

创建请求 
export async function login(data: IUserParam): Promise<BaseResponse<IUser>> {
  return (await NetWorkUtil.createAPI('/登录', 'GET', data))
    .data;
}

以上均为我不成熟的代码.各位根据需求来

如果支持RESTful方法,可以利用Record改成如下方式

enum IHttpMethods {
    GET = 'get',
    POST = 'post',
    DELETE = 'delete',
    PUT = 'put',
}

const methods = ["get", "post", "delete", "put"];

interface IHttpFn {
    <T = any>(url: string, config?: AxiosRequestConfig): Promise<T>
}

type IHttp = Record<IHttpMethods, IHttpFn>;

const httpMethods: IHttp = methods.reduce((map: any, method: string) => {
    map[method] = (url: string, options: AxiosRequestConfig = {}) => {
        const { data, ...config } = options;
        return (axios as any)[method](url, data, config)
            .then((res: AxiosResponse) => {
                if (res.data.errCode) {
                    //todo somethins
                } else {
                    //todo somethins
                }
            });
    }
    return map
}, {})

export default httpMethods;
————————————————
版权声明:本文为CSDN博主「问白」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38080573/article/details/92838045

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章