Introduction to the

Axios is a Promise based HTTP web library for browsers and Node.js.

The outline

Installation:

npm install axios
Copy the code

Use:

// insert axios const axios = require('axios');
import axios from 'axios';
Copy the code

Four ways to use Axios

1. axios(config)

The related configuration, including the request URL, is passed directly into the AXIOS method as a parameter

axios({
    url: 'https://jsonplaceholder.typicode.com/todos/1',
    method: 'get'
}).then(response => {
    console.log(response.data)
}).catch(error => {
    console.log(error)
});
Copy the code
2. axios(url[, config])

The AXIos method is used again, but the first parameter is passed in the request URL, and the second parameter is passed in the other configuration parameters.

axios('https://jsonplaceholder.typicode.com/todos/1', {
    method: 'get'
}).then(response => {
    console.log(response.data)
}).catch(error => {
    console.log(error)
});
Copy the code
3. axios[method](url[, config])

Use axios to expose the get, POST,delete,put and other request methods with the same parameter Settings as the second axios(url[, config]).

axios.get('https://jsonplaceholder.typicode.com/todos/1', {
    timeout: 1000
}).then(response => {
    console.log(response.data)
}).catch(error => {
    console.log(error);
});
Copy the code
4. axios.request(config)

Use the request method exposed by AXIos with the same parameter Settings as the first axios(config)

axios.request({
    url: 'https://jsonplaceholder.typicode.com/todos/1',
    timeout: 1000
}).then(response => {
    console.log(response.data)
}).catch(error => {
    console.log(error)
});
Copy the code

Request configuration

You can see the config parameter in the request method in the previous step. You can configure the request by setting the value of this parameter. In AXIos, config is the bridge between the caller and the network library,

Common configuration items are as follows:

{// 'url' is the server URL used for the request, relative path/absolute path URL:'/api/users'// 'method' is the HTTP method used to create a request, including get, POST, PUT, delete, etc.'get'// default // baseURL will automatically precede the url unless the url is an absolute URL. // It can facilitate passing the relative URL baseURL to axios instance methods by setting a 'baseURL' :'https://some-domain.com/api/', // 'transformRequest' allows request data to be modified before it is sent to the server'PUT'.'POST''PATCH'The following array functions must return a string, either an ArrayBuffer, or a Stream transformRequest: [function(data, headers) {// Perform any conversion on datareturndata; }], // 'transformResponse' is passed tothenThe response data is allowed to be modified before a catch.function(data) {// Perform any conversion on datareturndata; }], // 'headers' is a custom request that will be sent.'X-Requested-With': 'XMLHttpRequest'}, // 'params' is the URL parameter to be sent with the request // Must be a plain object or URLSearchParams object params: {name:'John'}, / / ` paramsSerializer ` is a ` params ` serialization functions / / (e.g., https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) paramsSerializer:function(params) {
   return Qs.stringify(params, {arrayFormat: 'brackets'})}, // 'data' is the data sent as the body of the request // only applies to these request methods'PUT'.'POST', and'PATCH'// When 'transformRequest' is not set, it must be one of the following types: // -string, plain Object, ArrayBuffer, ArrayBufferView, URLSearchParams  Stream data: { firstName:'John'}, // 'timeout' specifies the number of milliseconds for the request to timeout (0 means no timeout) // If the request takes longer than 'timeout', the request will be interrupted. 1000, // Adapter allows custom processing of requests to make testing easier // Return a promise and apply a valid response (see [Response Docs]) (#response-api)).
 adapter: function(config) { /* ... */}, // 'auth' indicates that HTTP base authentication should be used and credentials provided // This sets an Authorization header that overrides any existing custom Authorization header set using 'headers' : { username:'janedoe',
   password: 's00pers3cret'}, // 'responseType' indicates the data type of the server response'arraybuffer'.'blob'.'document'.'json'.'text'.'stream'
 responseType: 'json'// default // 'responseEncoding' indicates the decoding method used to respond to data.'utf8', // default // 'validateStatus' defines a resolve or reject PROMISE for a given HTTP response status code. If 'validateStatus' returns'true'(or set to' null 'or' undefined '), promises will be resolved; Otherwise, the Promise will be rejecte validateStatus:function (status) {
   returnstatus >= 200 && status < 300; CancelToken 'cancelToken' cancelToken: new cancelToken (cancelToken)function (cancel) {
 }),
 ...
}
Copy the code

The interceptor

Interceptors, a middleware like concept, are one of axios’s core features and are divided into two main types: request interceptors and response interceptors. With interceptors, we can process the network request configuration before the network request is made. Process the returned data before returning it.

Middleware, interceptor: Typically used for pre – or post-slicing of a target method, to manage some extra dirty logic in other files, improving the simplicity of the target method.

Usage:

/ / request interceptor const requestInterceptor = axios. Default. Interceptors. Request. Use ((config) = > {/ / before the request is sent, Do some processing on the request configuration (AxiosRequestConfig)return config;
}, (error) => {
   returnPromise.reject(error); }); / / remove before adding the interceptor axios. Default. Interceptors. Request. Eject (requestInterceptor); / / response interceptor axios. Default. Interceptors. Response. Use ((response) = > {/ / do some processing of the request and response datareturn response;
}, (error) => {
   return Promise.reject(error);
});

Copy the code

Cancel the request

Support for cancellation requests is also a core axios feature, which can be cancelled by implementing a cancelToken parameter in the configuration.

// Cancel request const cancelToken = axios.canceltoken; constsource = cancelToken.source();

axios.get('https://jsonplaceholder.typicode.com/todos/1', {
   cancelToken: source.token
}).then(response => {
   console.log(response.data);
}).catch(error => {
   if(axios.isCancel(error)) {
       console.log(error.message);
   } else {
       console.log(error)
   }
});

source.cancel('canceled by user');
Copy the code

The default configuration

Request configuration can be set individually in each request or globally in defaults.

// baseUrl axios.defaults.baseUrl ='https://jsonplaceholder.typicode.com'; // Default timeout time axios.defaults.timeout = 3000; / / the default Authorization header mon [axios.defaults.headers.com'Authorization'] = 'AUTH_TOKEN'; Data transfer request data conversion axios. Defaults. TransformRequest. Push ((data, headers) = > {/ / data processing the requestreturn data;
});
Copy the code

Return data conversion

Axios. Defaults. TransformResponse. Push ((data, headers) = > {/ / deal with the data returnedreturn data;
});
Copy the code

The source code parsing

Source code analysis is based on version 0.19.2

First look at the source directory structure:

Analysis of the request

We’ll start with several axiOS requests, an AXIOS object imported from the AXIOS library. Find the source axios.js class and you can see the default AXIos object created.

//axios.js

functioncreateInstance(defaultConfig) { var context = new Axios(defaultConfig); / / / / will create Axios instance context is bound to the request of Axios / / can also achieve methods: var instance = Axios. Prototype. Request. Bind (context); // Instance refers to the request method, and the context is instance context // so we can send the request directly in axios(URL, {config}). It's essentially the request method called var instance =bind(Axios.prototype.request, context); // Copy axios. Prototype to instance. // Copy axios. Prototype to instance. // So we can send the request utils. Extend (instance, axios.prototype, context) as axios.get/post; / / will the properties and methods on the context to expand on the instance / / so we have to axios. Defaults, axios. Interceptors can get to the interceptor and default attributes / / Copy the context to the instance utils.extend(instance, context);return instance;
}

// Create the default instance to be exported
var axios = createInstance(defaults);

module.exports = axios;
Copy the code

As you can see from the source code above, the axios object exported from axios is created using the createInstance method and default configuration defaults. Instead of just creating an Axios instance, the createInstance method does a bunch of binding and stretching to get an Axios instance that supports both Axios (URL,{config}) and axios.get/post requests.

Axios class and request method analysis

As you can see from the previous analysis, both the default instance created and the instance created with a custom configuration, as well as several ways to write an AXIOS request, are closely related to the AXIos class and the Request method.

functionAxios(instanceConfig) { this.defaults = instanceConfig; Request: new InterceptorManager(), response: new InterceptorManager()}; } Axios.prototype.request =function request(config) {
    if (typeof config === 'string') {/ / in order to support axios (url, {config}) this orthography config = the arguments [1] | | {}; config.url = arguments[0]; }else{ config = config || {}; } config = mergeConfig(this.defaults, config); // Merge configuration // set request methodif (config.method) {
    config.method = config.method.toLowerCase();
  } else if (this.defaults.method) {
    config.method = this.defaults.method.toLowerCase();
  } else {
    config.method = 'get'; } // Support interceptor middleware with chained arrays of promise resolve, reject values, Var chain = [dispatchRequest, undefined]; var chain = [dispatchRequest, undefined]; var promise = Promise.resolve(config); this.interceptors.request.forEach(functionunshiftRequestInterceptors(interceptor) { chain.unshift(interceptor.fulfilled, interceptor.rejected); // request interceptor inserted in front of array}); this.interceptors.response.forEach(functionpushResponseInterceptors(interceptor) { chain.push(interceptor.fulfilled, interceptor.rejected); // the response interceptor is inserted at the end of the array});while(chain.length) {// Traversal generates the final request promise(contains configuration information, request interceptor, dispatchRequest method, Response interceptor) promise = promise.then(chain.shift(), chain.shift()); }returnpromise; }; // to support axios.get(url, config) utils. ForEach (['delete'.'get'.'head'.'options'].function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    returnthis.request(utils.merge(config || {}, { method: method, url: url })); }; }); // to support axios.post(url, data, config) utils.'post'.'put'.'patch'].function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});
Copy the code

The Axios class has default configuration and interceptor values, as well as Axios’ core method request.

  • The request method declares a single parameter,config, but cleverly supports axios(URL,config) by determining if config is a string.
  • config = mergeConfig(this.defaults,config); Merges the default configuration with the configuration set on the request. Combined with the code for the CREATE factory method in the AXIos class, you can see that the configuration information in descending order of precedence is the default of > create AXIOS instance > AXIos on the request method
  • Axios supports promises by stuffing dispatchRequest, request interceptors, and response interceptors into an array in the Request method along with the arguments in the THEN method in the Promise, a group of resolve and reject.
// A brief flow for axios internal promises promise.resolve (config).then(function requestInterceptorFulfill(config) {
    return config;
  }, function requestInterceptorReject(error) {
    return Promise.reject(error);
  }).then(function dispatchrequest(config) {
    return dispatchRequest(config);
  }, undefined).then(function responseInterceptorFulfill(response) {
    return response;
  }, function responseInterceptorReject(error) {
    return Promise.reject(error);
  });
Copy the code

DispatchRequest analysis

From the source code above, you can see how Axios supports interceptors and where Config flows internally. There’s a dispatchRequest method that hasn’t analyzed what it does yet.

DispatchRequest = dispatchRequest = dispatchRequest = dispatchRequest

1. Support to cancel the request 2. Convert the request data 3. Request 5 is sent using the network request adapter Adapter and config. Convert the returned data

module.exports = functionDispatchRequest (config) {/ / if set cancelToken directly cancel request, the subsequent will analyze the related source throwIfCancellationRequested request (config); / / make sure headers exist config. Headers = config. The headers | | {}; Config. data = transformData(config.data, config.headers, config.transformRequest); / / merge headers config. Headers = utils. Merge (config.headers.com mon | | {}, config. The headers/config. Method | | {}, config.headers ); utils.forEach( ['delete'.'get'.'head'.'post'.'put'.'patch'.'common'].functioncleanHeaderConfig(method) { delete config.headers[method]; }); // Get the network request adapter set on config (if not, use the default) // There are two predefined adapters in AXIos: Respectively is the HTTP and the browser in nodejs XMLHttpRequest var adapter = config. Adapter | | defaults. The adapter. // Pass config into adpater,returnThis promisereturn adapter(config).then(functionOnAdapterResolution (response) {/ / if set cancelToken directly request throwIfCancellationRequested (config); Response. data = transformData(response.data, response.headers, config.transformResponse);return response;
  }, function onAdapterRejection(reason) {
    if(! isCancel(reason)) { throwIfCancellationRequested(config); // Convert the returned dataif(reason && reason.response) { reason.response.data = transformData( reason.response.data, reason.response.headers, config.transformResponse ); }}return Promise.reject(reason);
  });
};
Copy the code

As you can see, even if you go inside the dispatchRequest method, you’re not actually sending the request. The source tells us that the request is sent from within the Adapter.

Adapter – XHR analysis

Within AXIos, two request adapters are defined by default, HTTP on the NodeJS side and XHR on the browser side. Here the main analysis of XHR source code.

XHR: XMLHttpRequest, specific usage can refer to MDN document developer.mozilla.org/en/docs/Web…

// XHR compact source code, removed some non-key module.exports =function xhrAdapter(config) {
  return new Promise(functionDispatchXhrRequest (resolve, reject) {var request = new XMLHttpRequest(); Var fullPath = buildFullPath(config.baseurl, config.url); // Initialize the request according to the data in config. // Open method three parameters are: Whether the request method, url, asynchronous / / https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer),true); / / set up to monitor the request onreadystatechange callback event request. The onreadystatechange =function handleLoad() {// responseHeaders ='getAllResponseHeaders' inrequest ? parseHeaders(request.getAllResponseHeaders()) : null; Var responseData =! config.responseType || config.responseType ==='text'? request.responseText : request.response; Var response = {data: responseData, status: request.status, statusText: request.statusText, headers: responseData, statusText: request.statusText, headers: responseData, statusText: request. responseHeaders, config: config, request: request }; // Return the Promise's reslove or Reject settle(resolve, reject, response) depending on the state of the response; request = null; }; // Set the onabort callback event request. Onabort =function handleAbort() {
          reject(createError('Request aborted', config, 'ECONNABORTED', request)); request = null; }; // Set the onerror callback event request.onerror = that listens to the requestfunction handleError() {
    
      reject(createError('Network Error', config, null, request)); request = null; }; // Set the onTimeout callback event request.ontimeout =function handleTimeout() {
      var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
      if (config.timeoutErrorMessage) {
        timeoutErrorMessage = config.timeoutErrorMessage;
      }
      reject(createError(timeoutErrorMessage, config, 'ECONNABORTED', request)); request = null; }; // cancelToken cancels the request if cancelToken is setif (config.cancelToken) {
          config.cancelToken.promise.then(functiononCanceled(cancel) { request.abort(); // Interrupt request reject(cancel); Reject request = null; // Reject request = null; }); }if(requestData === undefined) { requestData = null; } request.send(requestData); // Use requestData to send the request}); };Copy the code

As you can see, the Adapter encapsulates the details of using XMLHttpRequest, including creating an XHR object, initializing a request, constructing a request link, setting request parameters, constructing a response object, and so on

Cancel request analysis

Previously, we talked about two kinds of cancel request usage, now analyze the cancel request related part of the source code.

//CancelToken.js
function CancelToken(executor) {

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if(token.reason) {// It has been cancelledreturn; } // Cancel class token.reason = new Cancel(message); resolvePromise(token.reason); }); //xhr.jsif(config. CancelToken) {/ / processing request of config. CancelToken. Promise. Then (function onCanceled(cancel) {
        if(! request) {return; } request.abort(); // Interrupt request reject(cancel); request = null; }); }Copy the code

Through the above source code, we know

This. Promise = new promise (function promiseExecutor(resolve) {resolvePromise = resolve; }); .

CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken: CancelToken The Cancel object is then passed out through the reslove method of the saved Promise.

3. In the XHR code, the cancel object of resolve, the second step, continues through the then method, where the request is interrupted, and is passed externally through XHR’s Promise Reject method. That’s what we get from the catch that we request using Axios.

4. When CancelToken is used, the cancel method in step 2 is saved and called like this when the request needs to be cancelled. cancel(‘Cancel by user! ‘). The method argument is message in the Cancel object.

To sort it out:

// XHR promise new promise ((resolve, reject)=>{letrequest = { abort: ()=>{ } }; //CancelToken promise. resolve(new Cancel('Cancel by User! ')).then(cancel => { request.abort(); // Interrupt request reject(cancel); }); }).catch(error => {if(axios.iscancel (error)) {// Reject the cancel object in XHR and print message console.log(cancer.message); }});Copy the code

Reference: 【 blog.csdn.net/qq_27053493 www.cnblogs.com/JohnTsai/p/… zhuanlan.zhihu.com/p/156862881 zhuanlan.zhihu.com/p/33918784 】