The introduction
Familiar with Vue students, must have used Axios, concise API syntax and convenient interceptor have been warmly welcomed by developers, behind the use, whether also want to understand the implementation principle, in fact, the source code is not difficult to read, here I will throw out a brick to introduce jade, to do a brief analysis of the source code
This article is intended for developers who use Axios a lot, so the following content assumes that the reader is familiar with or proficient in Axios and does not provide a detailed description of Axios functionality
This article, the first in a series, examines the Axios export instance and the default configuration
The Axios version analyzed in this article is 0.21.0
review
Let’s start by reviewing the common Axios features
-
axios(config) / axios.get / axios.post / axios.delete ….
Call AXIos, pass in a request, or make a get, POST, delete request directly
-
axios.create
Create a new axios instance
-
axios.defaults.xxxx
Configure the default configuration of AXIOS
-
axios.interceptors.request / axios.interceptors.response
Configure global interceptors for AXIOS, or you can configure interceptors only for an instance created through CREATE
-
cancel
Cancel a request
Next we according to the source code one by one analysis, the above function is how to achieve
The code structure
The main directory in the source code is lib, and the rest are unit tests, documentation, etc., which I won’t go into here
Lib │ axios.js │ defaults. Js │ ├─ Adapters │ HTTP.js │ Readme.md │ XHR. Js │ ├─ Cancel │ Cancel Canceltok.js │ isCancel. Js │ ├─core │ axios.js │ buildFullPath.js │ createError.js │ dispatchRequest.js │ EnhanceError. Js │ interceptormanager.js │ mergeConfig. Js │ readme. md │ settle buildURL.js combineURLs.js cookies.js deprecatedMethod.js isAbsoluteURL.js isAxiosError.js isURLSameOrigin.js normalizeHeaderName.js parseHeaders.js README.md spread.jsCopy the code
There are several important files (axios.js, defaults.js, utils.js) and several classes of files in four separate folders
-
axios.js
This file serves as an entry file for generating and exporting AXIos objects, as well as extending a series of functional methods such as axios.create
-
defaults.js
This file is the default configuration
-
utils.js
This file is a series of helper methods, such as isStirng, extend, and so on
-
adapter
This directory is where the adaptors for Ajax, namely HTTP libraries that encapsulate native xmlHttpRequest or Node, are processed into their own methods for easy use. If there are newer Ajax methods, such as FETCH, Axios just needs to modify this part to fit the new interface
-
cancel
This implements the function of canceling the request
-
core
This is the core code of Axios, including Axios base class, some error wrapper, etc. The core code is axios.js, dispatchRequest.js, interceptorManager.js
-
helpers
The other helper functional modules here are probably different from utils.js because utils.js is a more general method, while the helper methods in this directory are custom
The Adapter directory is useful because it uses the adapter pattern in design pattern, which can be read further if you are interested
Source code analysis
Axios (config)/axios.get/axios.create and other methods
Instead of focusing on the implementation, let’s see how to expose abstract methods for developers to use, focusing on lib/axios.js
/ / path: lib/axios. Js
var utils = require('./utils');
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var mergeConfig = require('./core/mergeConfig');
var defaults = require('./defaults');
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;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
axios.Cancel = ...
axios.CancelToken = ...
axios.isCancel = ...
axios.all = ...
axios.spread = ...
axios.isAxiosError = ...
module.exports = axios;
Copy the code
As you can see, the axios that our developers are using is also an instance of the axios base class (not a pure instance, strictly speaking).
If you want to export an instance of axios(config)/axios.get/axios.create, you can export an instance of axios(config)/axios.get/axios.create To extend this instance to make it more powerful, let’s take a step-by-step look at how this is done:
-
var context = new Axios(defaultConfig); var instance = bind(Axios.prototype.request, context); Copy the code
These two lines generate an instance context, bind this, the context of the request method of the base class Axios, to the instance context, and generate a new method instance, which will be the Axios object we’ll use in the future, At this point, the AXIos object is essentially just a Request method
Bind is the es6 equivalent of the function.prototype. bind method, except axios implements it itself here for compatibility
-
utils.extend(instance, Axios.prototype, context); Copy the code
In this step, extend merges axios.prototype’s prototype chain into instance (Request), which is redundant because instance’s prototype also contains its request method. Here we implement axios(config) (equivalent to axios.request(config)) and axios.get/axios.post… (Prototype chain method) these several functions
Prototype extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends
-
utils.extend(instance, context) Copy the code
This step, again using the extend method, merges other properties of the context, such as defaults and Interceptors, into the instance object
-
axios.create = function create(instanceConfig) { return createInstance(mergeConfig(axios.defaults, instanceConfig)); }; Copy the code
This extends the createInstance function to axios.create, allowing developers to create new instances, as well as the Cancel, all, and other methods
Finally, we have an objectaxios
It looks likeAxios
An instance of the class, which also acts like an instance, is just onerequest
Method, but with instance properties and stereotypes, and some other apis
When I was younger, I took it for granted that an instance created by axios.create could be subclassed by create. Now I read the source code and realized that there was no such design. I was at the fifth layer and the author was at the second.
The default configuration of AXIos
Before diving into the logic, let’s take a look at the default configuration of Axios, how to change the global configuration, and how to differentiate instance configuration
Take a look back at the code above and the Axios base class
// lib/core/Axios.js
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
Copy the code
// lib/axios.js
var defaults = require('./defaults');
// Create the default instance to be exported
var axios = createInstance(defaults);
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
Copy the code
Global configuration is a file that binds an instance to the axios object’s defaults property by creating a new instance. Subsequent instances created by axios.create are merged with axios.defaults and instantiated. Axios.defaluts becomes a global configuration, and changing this property affects the AXIos object and all instances derived from it, which has its own defaults object on it and only affects itself
Let’s take a look at the specific default configurations
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
};
function getDefaultAdapter() {
var adapter;
if (typeofXMLHttpRequest ! = ='undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
} else if (typeofprocess ! = ='undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/http');
}
return adapter;
}
var defaults = {
adapter: getDefaultAdapter(),
transformRequest: [...]. .transformResponse: [...]. .timeout: 0.xsrfCookieName: 'XSRF-TOKEN'.xsrfHeaderName: 'X-XSRF-TOKEN'.maxContentLength: -1.maxBodyLength: -1.validateStatus: function validateStatus(status) {
return status >= 200 && status < 300; }}; defaults.headers = {common: {
'Accept': 'application/json, text/plain, */*'}}; utils.forEach(['delete'.'get'.'head'].function forEachMethodNoData(method) {
defaults.headers[method] = {};
});
utils.forEach(['post'.'put'.'patch'].function forEachMethodWithData(method) {
defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});
module.exports = defaults;
Copy the code
Some of the details are omitted here, and you can go to the source code for more details, but what you might think is that the original document is not the default configuration at all, it just lists all the available configurations and what values should be passed, and the actual default configuration is only the ones in the file above
-
adapter
It matches the lib/adapters/xhr.js and lib/adapters/http.js files.
-
TransformRequest and transformResponse
If you just want to add a new transform rule, I recommend adding a new transform rule based on the default:
axios.defaults.transformRequest = [ ...axios.defaults.transformRequest, ...customerTransform ]
-
Timeout, xsrfCookieName, xsrfHeaderName, maxContentLength, maxBodyLength, validateStatus
These configurations are easy to understand and won’t be described here
-
headers
The default header has a general Accept header, and then distinguishes the request types. Only ‘POST ‘,’ PUT ‘, and ‘patch’ will have the default ‘content-Type ‘: Application /x-www-form-urlencoded’ application/json’
conclusion
In the second part, I will go into the core of the request request and the implementation of the interceptor. As a brick lifter, I have limited ability. If there are children who do not understand this part and feel that I did not describe clearly, you can discuss in the comments section