Axios (一)

axios应该是目前最为常用的前端ajax请求框架, 此次将分四天实现手写Axios源码

  • 第一天: 实现基础极简版axios
  1. 创建基础类型: types.ts文件:
// 定义请求方法的类型
export type Methods = 'GET' | 'POST' | 'get' | 'post' | 'put' | 'PUT' | 'delete' | 'DELETE' | 'options' | 'OPTIONS'
// 定义axios请求的配置类型,及 axios({})方法中的配置对象类型
// 这里只定义三个基础的配置参数,仅支持get请求的配置
export interface AxiosRequestConfig {
  url: string;
  method: Methods;
  params: any;
}

// axios请求实例的类型, 及就是导出的axios instance的类型
// Promise的泛型T代表Promise编成成功太之后resolve的值的类型
export interface AxiosInstance {
  <T = any>(config: AxiosRequestConfig): Promise<T>
}

// axios请求成功后响应的类型
// 泛型T代表响应体的类型
export interface AxiosResponse<T = any> {
  data: T;
  status: number;
  statusText: string;
  headers?: Record<string, any>;
  config?: AxiosRequestConfig,
  request?: XMLHttpRequest
}
  1. 定义axios入口文件: index.ts, 定义基础的createInstance方法创建axios实例:
// 这里引入Axios类,将会在之后进行定义
import Axios from "./Axios"
import { AxiosInstance } from "./types"

// 用于创建一个axios实例
function createInstance() : AxiosInstance {
  let context: Axios = new Axios();  // 之后绑定this指针的上下文
  // 让request方法里的this永远指向context, 也就是new Axios()的实例
  let instance = Axios.prototype.request.bind(context)
  // 把Axios类的实例和类的原型上的方法都拷贝到instance上,也就是request方法上
  instance = Object.assign(instance, Axios.prototype, context);
  return instance as AxiosInstance;
}
// 这里获取到的axios实例就是在createInstance方法中创建的instance实例,类型为AxiosInstance
let axios = createInstance();
export default axios;

// 同时从入口文件导出axios中的类型定义
export * from "./types"
  1. 定义axios类文件: Axios.ts,主要实现request方法
import { AxiosRequestConfig, AxiosResponse } from "./types"
// qs库的作用类似于querystring库,将query参数进行转化
import qs from "qs";
// parseHeader库的作用是将http请求返回的header字符串转化为对象
import parseHeader from "parse-headers";

export default class Axios {
  // 泛型T用来限制响应对象里的response里的data的类型
  request<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.dispatchRequest(config)
  }

  // 定义一个派发请求的方法a
  dispatchRequest<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return new Promise<AxiosResponse<T>>(function (resolve, reject) {
      let { method, url, params } = config;
      let request = new XMLHttpRequest();  // 创建xhr对象
      if (params && typeof params === 'object') {
         // 如果params有值并且是一个对象的话,需要拼接成一个字符串放到url后面
        // 转化的形式: {name: "chensir", age: 20} => name=chensir&age=20
        params = qs.stringify(params);
      }
      url += ((url.indexOf('?') > 0 ? '&' : '?') + params);  // 将params参数拼接到url后面
      request.open(method, url, true);
      request.responseType = "json";  // 设定请求返回的数据类型json类型
      request.onreadystatechange = function () {
        // 指定状态变更监听函数
        if (request.readyState === 4) {
          if (request.status >= 200 && request.status < 300) {
          	// 请求成功,构建返回的AxiosResponse响应对象
            let response: AxiosResponse<T> = {
              data: request.response ? request.response : request.responseText,
              status: request.status,
              statusText: request.statusText,
              headers: parseHeader(request.getAllResponseHeaders()),
              config,
              request
            }
            resolve(response)
          } else {
            reject("请求失败")
          }
        }
      }
      request.send();
    })
  }
}

此部分仅仅实现了axios最简单的get请求操作,许多内容会在之后进行改进…

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐