手写简易版的Axios

187 阅读2分钟

axios的简介

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

基本用法

// 发送 POST 请求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

实现功能

  • Axios实例对象生成
  • 如何发起请求(适配器)
  • 拦截器
  • 取消请求

生成Axios实例对象

// default.jsfunction xhr(config) {
  return new Promise((resolve, reject) => {    var request = new XMLHttpRequest();    request.open(config.method.toUpperCase(), config.url, true);    request.onreadystatechange = function() {      var response = {        data: request.response,        status: request.status,        statusText: request.statusText,        headers: request.getAllResponseHeaders(),        config: config,        request: request,      };      resolve(response);    };    request.send(config.data);  });}function http() {}// 根据环境获取适配器function getDefaultAdapter() {  var adapter;  if (typeof XMLHttpRequest !== "undefined") {    // For browsers use XHR adapter    adapter = xhr;  } else if (    typeof process !== "undefined" &&    Object.prototype.toString.call(process) === "[object process]"  ) {    // For node use HTTP adapter    adapter = http;  }  return adapter;}// 默认值const defaults = {    // 适配器  adapter: getDefaultAdapter(),  method: "get",};export default defaults;

// Axios.jsfunction dispatchRequest(config) {    var adapter = config.adapter || defaults.adapter;    adapter(config).then(response => {        console.log(response)    }) }function Axios(instanceConfig) {  this.defaults = instanceConfig;  this.interceptors = {    request: {},    response: {},  };}Axios.prototype.request = function(config) {  config = { ...this.defaults, ...config };  const promise = dispatchRequest(config);  return promise};
// axios.jsvar axios = createInstance(defaults);

在axios中传入defaults值,其他有适配器adapter,通过适配器采用不同的请求方法,此处只实现了浏览器中的请求方法xhr。axios是基于Promise的,所以xhr中返回的是一个promise对象,将在dispatchRequest中调用then返回

拦截器

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

上面是拦截器的用法,我们在Axios构造函数中声明了一个interceptors对象,interceptors对象有request和response两个属性,分别代表请求拦截器实例和响应拦截器实例,拦截器实例中有handlers数组,当调用use方法,往里面push拦截器方法,因为是promise,所以需要添加两个表示成功和失败的回调,request方法中执行拦截器。

请求拦截器 handlers中为[1,2],requestInterceptorChain中使用unshift方法变为[2,1]再执行;响应拦截器 handlers中为[1,2],responseInterceptorChain中使用push方法方法变为[1,2]再执行;最终的结果是“请求拦截2, 请求拦截1, 响应拦截1, 响应拦截2“

function Axios(instanceConfig) {  
    this.defaults = instanceConfig;  
    this.interceptors = {    
        request: new InterceptorManager(),    
        response: new InterceptorManager()
    };
}
function InterceptorManager() {  
    this.handlers = [];
}
InterceptorManager.prototype.use = function(fulfilled, rejected) {  
    this.handlers.push({fulfilled,rejected});
    return this.handlers.length - 1;
};
InterceptorManager.prototype.forEach = function(fn) {  
    this.handlers.forEach((handler) => {    
        fn(handler);  
});
};
Axios.prototype.request = function(config) {  
    config = { ...this.defaults, ...config };  
    let promise;  
    let requestInterceptorChain = [];  
    this.interceptors.request.forEach(function(interceptor) {    
        requestInterceptorChain.unshift(interceptor.fulfilled,interceptor.rejected);
    });  
    var responseInterceptorChain = [];  
    this.interceptors.response.forEach(function(interceptor) {
        responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);  
    });  
    var newConfig = config;  
    while (requestInterceptorChain.length) {
        var onFulfilled = requestInterceptorChain.shift();
        var onRejected = requestInterceptorChain.shift();
        newConfig = onFulfilled(newConfig);
        break;   
     }  
    }  
   promise = dispatchRequest(newConfig);  
   while (responseInterceptorChain.length) {    
    promise = promise.then(      
        responseInterceptorChain.shift(),      
        responseInterceptorChain.shift()    
    );  
   } 
    return promise;
};