easy-axios

目的

  • axios默认值、参数实现
  • 实现一个简单get请求
  • 实现XHLHttpRequest
  • axios拦截器

准备

零配置的打包工具 Parcel ,使用方式也很简单,在你的客户端目录下通过 npm init -y 初始化,通过 npm install parcel-bundler –save-dev 安装 Parcel ,然后在你的 package.json 文件中添加如下脚本:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "parcel ./*.html",
    "build": "parcel build ./*.html"
  },

开始

新建axios文件夹,在此文件夹下新建

  • axios.js //主要代码,包括axios.create等方法的实现
  • default.js //默认的参数
  • index.js //就是一个导出文件
  • Interceptor.js //拦截器
  • mergeConfig.js //合并配置默认值和用户的自定义配置(直接拷的源码)
  • request.js //XMLHttpReauest发请求
  • utils.js //工具类函数 (直接拷的源码)

主要文件就是这些,
贴几份我觉的比较重要的代码

这里是在Axios类的prototype上新增create方法并在里面new了一个Axios实例同时给实例添加默认配置参数

Axios.create = Axios.prototype.create = function (config) {
  let configOptions = mergeConfig(defaults, config);
  console.log(configOptions, "configOptions");

  let axios = new Axios(configOptions);
  axios.defaultConfig = configOptions;
  return axios;
};

请求的实现 利用Promise包裹原始请求,使之可以链式调用

export default function request(options) {
  let xhr = new XMLHttpRequest();
  xhr.open(options.method, options.url);
  for (let key in options.headers) {
    xhr.setRequestHeader(
      encodeURIComponent(key),
      encodeURIComponent(options.headers[key])
    );
  }
  xhr.send(options.data);
  return new Promise((resolve, reject) => {
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
          console.log(xhr);
          resolve({
            data: JSON.parse(xhr.responseText),
            status: xhr.status,
            statusText: xhr.statusText,
          });
        } else {
          reject(xhr);
        }
      }
    };
  });
}

request 和response拦截器

拦截器的使用方法

axios.interceptors.request.use((config) => {
  config.headers.token = "x-token-654321";
  return config;
});

//响应拦截器
axios.interceptors.response.use((res) => {
  console.log("请求响应信息", res);
  return res;
});

所以在Axios 的构造函数里

constructor() {
    this.interceptors = {
      request: new Interceptor(),
      response: new Interceptor(),
    };
  }

Interceptor 类的实现如下

class Interceptor {
  constructor() {
    this.handlers = [];
  }
  use(fulfilled, rejected) {
    this.handlers.push({
      fulfilled: fulfilled,
      rejected: rejected,
    });
    return this.handlers.length - 1;
  }
}

要实现在发请求之前调用request拦截器,在请求结束后调用response拦截器
就要如下,利用Promise.resolve 和promise.then()进行链式调用

request(config) {
    let configOptions = mergeConfig(this.defaultConfig, config);
    let promise = Promise.resolve(configOptions);
    //请求拦截器
    let requestHandlers = this.interceptors.request.handlers;
    requestHandlers.forEach((handeler) => {
      promise = promise.then(handeler.fulfilled, handeler.rejected);
    });
    //数据请求

    promise = promise.then(request);//这里的request是promise包裹的XMLHttpRequest
    //响应拦截器
    let responseHandlers = this.interceptors.response.handlers;
    responseHandlers.forEach((handler) => {
      promise = promise.then(handler.fulfilled, handler.rejected);
    });
    return promise;
  }

感觉就是一个发布订阅模式,在调用interceptors.request.use(fn,fn)或者interceptors.reponse.use(fn,fn)时,将需要执行的函数订阅(储存在数组)在调用request时发布(执行所有的函数)

具体代码 https://github.com/dz333333/esay-axios

这里仅仅是很简单的实现,而且只是实现了get请求,源码里面还有各种的优化,路径,协议,参数等等各种处理还有取消请求的方法,all方法

发表评论

您的电子邮箱地址不会被公开。