This is the 23rd day of my participation in the August More Text Challenge.More challenges in August

1. Axios introduction and basic use

Axios is a Promise-based HTTP library that can be used in browsers and Node.js and supports the following features:

  • Create XMLHttpRequests from the browser
  • Create HTTP requests from Node.js
  • Supporting Promise API
  • Intercept requests and responses
  • Transform request and response data
  • Cancel the request
  • Automatic conversionJSONdata
  • The client supports XSRF defense

Reference:

axios-http.com/

www.npmjs.com/package/axi…

github.com/axios/axios

2, AXIOS source – AXIos class

The Axios class is the core class that encapsulates and provides the API used by the request.

/ / Axios class
function Axios() {
  / / initialization
}
Axios.prototype.request = function(config) {
  // Axios unified request entry method
}
Copy the code

Axios also provides a list of HTTP method alias functions based on the request method:

// Provide aliases for supported request methods
// Encapsulate requests that do not need to submit body data
utils.forEach(['delete'.'get'.'head'.'options'].function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(mergeConfig(config || {}, {
      method: method,
      url: url,
      data: (config || {}).data
    }));
  };
});
// Handle requests that can submit body data
utils.forEach(['post'.'put'.'patch'].function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(mergeConfig(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});
Copy the code

6, Axios source code – factory functions

Axios provides a function createInstance to assist in creating an instance of the Axios class. Note, however, that instead of returning an Axios instance object, this function returns the instance object’s Request method, and mounts the instance object’s other alias methods to the Request method (functions are also objects, and attribute methods can be added). Hence the following usage:

axios({... }); axios.get('/', {...})
...
Copy the code
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  var instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context);

  return instance;
}
Copy the code

When we reference the Axios library, it internally calls createInstance to initialize and returns Request:

varaxios = createInstance(defaults); .module.exports = axios;
// This is written to be compatible with the default export of the ESM module
module.exports.default = axios;
Copy the code

It also provides a few other methods for the exported AXIos:

Original class

// Mount the original Axios class
axios.Axios = Axios;
Copy the code

The factory function

// Create the instance's factory function
axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
Copy the code

So, we can create another AXIos request using the factory function:

// Use the default request
axios.get('/user');

// Use the new configuration to send the request
let newRequest = axios.create({baseURL: 'http://localhost:9999'});
newRequest.get('/user');
Copy the code

3, AXIos source code – configuration processing

There are three configuration points in Axios:

  • Request method configuration
  • The instance configuration
  • Global configuration

Reference: axios-http.com/zh/docs/req…

Request method configuration

Is the configuration passed in request and alias methods such as GET and POST

axios({
  url: '/user'
});
axios.get('/user', {
  params: {
    page:1.limit:2}})...Copy the code

Instantiate configuration

We can also pass in the base configuration at instantiation time (we can pass in some of the requested common configurations at instantiation time)

let newRequest = axios.create({
  baseURL: 'http://localhost:9999'
});
Copy the code

Global (default) configuration

Axios also has a set of default configuration items, which are used if none are passed in at instantiation time or if the instantiation axios exports by default.

// The default configuration can be obtained via axios.defaults
axios.defaults.baseURL = 'http://localhost:8888';
axios.get('/user');
Copy the code

Configuring a Priority

Request Configuration > Instance Configuration > Default Configuration

4, AXIOS source code – interceptor application and implementation

There is a middleware-like mechanism in AXIos to handle tasks before the Request method requests them and after the response (before the user code executes).

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response;
  }, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
  });
Copy the code

Reference: axios-http.com/zh/docs/int…

Interceptor source code

Interceptors are essentially middleware arrays with two groups: requests and responses

function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}
Copy the code
// Interceptor execution
Axios.prototype.request = function request(config) {...var requestInterceptorChain = [];
  var synchronousRequestInterceptors = true;
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
      return;
    }

    synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;

    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  var responseInterceptorChain = [];
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  });

  var promise;

  if(! synchronousRequestInterceptors) {var chain = [dispatchRequest, undefined];

    Array.prototype.unshift.apply(chain, requestInterceptorChain);
    chain.concat(responseInterceptorChain);

    promise = Promise.resolve(config);
    while (chain.length) {
      promise = promise.then(chain.shift(), chain.shift());
    }

    return promise;
  }


  var newConfig = config;
  while (requestInterceptorChain.length) {
    var onFulfilled = requestInterceptorChain.shift();
    var onRejected = requestInterceptorChain.shift();
    try {
      newConfig = onFulfilled(newConfig);
    } catch (error) {
      onRejected(error);
      break; }}try {
    promise = dispatchRequest(newConfig);
  } catch (error) {
    return Promise.reject(error);
  }

  while (responseInterceptorChain.length) {
    promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
  }

  return promise;
}
Copy the code

Interceptor application

// Add request interceptor
axios.interceptors.request.use(function (config) {
    / / send the token
    try {
      let token = localStorage.getItem('token');
      config.headers.authorization = token;
    } catch(e){}
    return config;
  }, function (error) {
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    console.log('Request Log', response);
    return response;
  }, function (error) {
    console.log('Request Log', response);
    alert('Wrong');
    return Promise.reject(error);
  });
Copy the code

5, AXIos source code – adapter

In the browser, we use the API provided by XMLHttpRequest to send the request. In node.js, we need to use the API provided by the HTTP module to send the request. The underlying API structure, including the formatting of the response data, is also inconsistent. Axios, in order to address this discrepancy and allow users to use the same API in different environments, uses adaptation mode.

graph RL
A[axios]
B[XMLHttpRequest Adapter] --> A
B1[XMLHttpRequest] --> B
C[Node.js Adapter] --> A
C1[Node.js] --> C