Hello everyone, today I am Zhuge Xiaoyu. For front-end development children’s shoes. In both Vue and React development, everyone should use the axios library recommended by the official. (what? You said Anglur didn’t recommend it! This classmate, please go out, with the door thank you!
First of all, we know axios is a great request library (available in browsers and Node.js) because before it we used Ajax four steps, using jQ ajax. Since JQ itself is a library, Ajax is also a function that it encapsulates and contains in its library, which is not pure at all. Ajax said, “A great man can’t stay under a heavy roof!” I want independent mountain!! ** Then Axios came along and a pure request-only library appeared.
Axios is a PROMISe-based HTTP library, documented at github.com/axios/axios. Then after understanding the origin of the emergence of the big brother, we will formally complete the matter, because the later to read the source code, so I believe that you should be able to accept this move, because after knowing Axios ox B, you can hit the door to take hold of the dead. Steady as you go, Ollie!
The following 6 points are only for those who have not carefully scanned the AXIos configuration. If you are particularly familiar with axios, please bypass the source code and read it directly.
Axios understands and uses
1. Request configuration
{
// Request the server URL
url: '/user'.// method Specifies the method used to create the request
method: 'get'
// baseURL will automatically precede the URL unless the URL is an absolute one
baseURL: 'https://some-domain.com/api/'
// 'transformRequest' allows you to modify request data before sending it to the server
// Can only be used with PUT, POST, and PATH request methods
// The function in the following array must return a string, either an ArrayBuffer, or a Stream
transformRequest: [function(data, headers) {
// Perform any conversion on data
return data;
}]
// 'transformResponse' allows modification of response data before passing it to then/catch
transformResponse: [function(data) {
// Perform any conversion on data
return data
}]
// 'headers' is the custom request header to be sent
headers: { 'X-Requested-With': 'XMLHttpRequest' }
// 'params' is the URL parameter to be sent with the request
// Must be a plain object or URLSearchParams object
params: {
ID: 12345
}
// 'paramsSerializer' is a function that serializes 'params'
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})}// 'data' is the data sent as the body of the request
// Only the request methods PUT POST PATHCH
// When 'transformRequest' is not set, one of the following types must be required:
// - string,plain object, ArrayBuffer,ArrayBufferView,URLSearchParams
// - Browser specific: FormData, File, Blob
// - Node exclusive: Stream
data: {
firstName: 'Fred'
}
// Specifies the number of milliseconds for the request to timeout (0 indicates no timeout)
// Request timeout, request will be interrupted
timeout: 1000
// 'withCreadentials' indicates whether credentials are needed to span a request
withCreadentials: true.// default -> false
// Adapter allows you to customize processing requests to make testing easier
adapter: function(config) {
/ * * /
}
// 'auth' indicates that HTTP basic authentication should be used and credentials provided
// This sets an 'Authorization' header that overrides any existing custom 'Authorization' set using 'hedaers'
auth: {
username: 'janedoe'.password: 's00pers3cret'
}
// 'responseType' indicates the data type of the server response, which can be 'arrayBuffer ', 'blob', 'document', or 'json'.
responseType: 'json'.// 'xsrfCookieName' is the name of the cookie worth the XSRF token
xsrfCookieName: 'XSRF-TOKEN'
// 'onUploadProgress' allows processing of progress events for uploads
onUploadProgress: function(progressEvent) {
// Do whatever you want with the native progress event
}
// 'onDownloadProgress' allows progress events to be handled for downloads
onDownloadProgress: function(progressEvent) {
// Handling of native progress events
}
// 'maxContentLength' defines the maximum size allowed for response content
maxContentLength: 2000
// 'validateStatus' defines resolve or reject promis for a given HTTP response status code
validateStatus: function(status) {
return status >=200 && status <300
}
// 'maxRedirects' defines the maximum number of redirects followed in Node.js
// If set to 0, no redirection will be followed
maxRedirects: 5.// default
// 'proxy' defines the host name and port of the proxy server
// 'auth' indicates that HTTP basic authentication should be used to connect to the proxy and provide credentials
// This will set a 'proxy-authorization' header to override any customizations already set using 'header'
proxy: {
host: '127.0.01'.port: 9000.auth: {
username: 'mikeymike'.password: 'rapunz3l'}}// 'cancelToken' specifies the cancel token used to cancel the request
cancelToken: new CancelToken(function(cancel) {})}Copy the code
2. Response structure
The response to a request contains the following information
{
// 'data' is the response provided by the server
data: {}
// 'status' is the HTTP status information from the server response
status: 200.// 'statusText' is the HTTP status information from the server response
statusText: 'OK'
// 'headers' is the header of the server response
headers: {}
// 'config' is the configuration information provided for the request
config: {}
request: {}}Copy the code
3. Axios characteristics
1. Asynchronous Ajax request library based on Promise.
2. It can be used on both the browser and node.
3. Support request/response interceptors.
4. Support cancellation requests.
5. Request/response data conversion.
6. Send multiple requests in batches.
4.axios.create(config)
1. Create a new AXIOS based on the specified configuration, that is, each new AXIOS has its own configuration
2. The new Axios just doesn’t have a way to cancel requests or batch requests, and everything else is the same syntax
3. Why design this syntax?
(1) Requirements: The configuration required by some interfaces in the project is different from that required by other interfaces. What should I do?
(2) Solution: Create two new AXIos, each with unique configuration, to be applied to interface requests with different requirements
5. Axios processing chain process
// Add request interceptor (callback function) -> Add after execute first
axios.interceptors.request.use(
config= > {
return config
},
error= > {
return Promise.reject(error)
}
)
// Add a response interceptor
axios.interceptors.response.use(
response= > {
return response
},
error= > {
return Promise.reject(error)
}
)
Copy the code
6. Cancel the request
let cancel // The function used to save the cancellation request
getProducts() {
// Cancel pending requests before you are ready to send them
if( typeof cancel === 'function' ) {
cancel('Cancel request')
}
axios({
url: 'http://localhost:8000/products1'.cancelToken: new axios.CancelToken((c) = > { // c is the function used to cancel the current request
// Save the cancel function, which may need to cancel the current request later
cancel = c;
})
}).then(
response= > {
cancel = null
consoel.log('Request successful')},error= > {
if(axios.isCancel(error)) {
console.log('Error cancelling request')}else { // Request error
cancel = null
console.log(error.message)
}
}
)
}
cancelReq() {
if(type cancel === 'function') {
cancel('Force cancel request')}else {
console.log('No cancelable request')}}/ / call
cancelReq()
Copy the code
If you have not read the above information, please read it carefully. If you have not read it, please recite it.
-
Unidentified lucky water buddy: Hold on, I have a question
-
Zhugexiaoyu: ha, you have a problem?
-
Zhugexiaoyu: what problem?
-
Unknown lucky water friend: see source code how to do……
Now it’s time for our official service. Play to play, make, don’t take the source code joke. In fact, the source code like Axios is relatively simple, I think for the source code or do a superficial taste of the line, you talk about the second and third layer in the interview, the interviewer may think you are in the fifth layer. It is not recommended to stop doing something unless it is of great benefit. At this time, you can see more excellent open source projects and make more progress.
Read the axios source code
1. File directory
Dist -> Package the generated file
Examples -> examples
Lib -> core file code
Adapters -> Request the relevant folder
Http.js -> node Server sends HTTP request
Xhr.js -> the module that actually makes the request
Cancel -> Cancel the folder associated with the request
Cancer.js -> defines the Cancel constructor
Canceltoken. js -> defines a constructor that performs canceltoken-related
Iscancel. js -> Determines whether an error is a cancel type error
Core -> something at the core
Axios.js -> Axios constructor
Dispathrequest.js -> Distribute the request
Interceptormanager.js -> interceptor related
Helpers -> tool module
Axios.js -> expose the axios function externally
Defaults.js -> things related to default configuration
Index.js -> Outer entry file
2. Relationship between Axios and Axios
Syntax: Axios is not an instance of axios.
② Functionally speaking: Axios is an instance of Axios. (1. It has its own attributes. 2. There are methods on his prototype chain)
Axios is the function returned by the axios. Prototype function bind()
(4) Axios as an object has all the methods on the Axios prototype object and all the properties on the AXIos object
Source axios.js file
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
* @return {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
/ / equivalent Axios. Prototype. Request. Bind (context)
// Bind returns a new function that calls the request function internally,
// The axios function finally finds request
// Context is an instance of Axios. Once you use this in the request function, it points to an instance of Axios
var instance = bind(Axios.prototype.request, context); // axios
// Copy the method from the Axios prototype object to instance: request()/get()/post()/put()/delete()
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
// Copy the properties from the Axios instance object to instance: the defaults and Interceptors properties
utils.extend(instance, context);
return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
Copy the code
3. The difference between Instance and Axios?
1. The same:
(1) is a function that can send any request: request(config)
Get ()/post()/put()/delete()
(3) Both have default configurations and interceptors attributes: defaults/ Interceptors
2. The different:
(1) Default matching values are likely to be different
(2) Instance does not have some methods added after axios: create()/CancelToken()/all()
Source axios.js file
// Factory for creating new instances
axios.create = function create(instanceConfig) {
// Call createInstance again
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// Expose Cancel & CancelToken
// The difference is that axios adds these operations, while axios.create does not
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);
};
Copy the code
4. The overall process that AXIos runs?
Main process:
request(config) == > dispatchRequest(config) ===> xhrAdapter(config)
Request (config) :
Chain the request interceptor/dispatchRequest()/response interceptor through the Promise chain, then the Promise
dispatchRequest(config) :
Convert the request data ===> Call xhrAdapter() to send the request === => Convert the response data after the request returns. Return to the promise
xhrAdapter(config):
Create an XHR object, set it according to config, send a specific request, receive the response data, and return a Promise.
Axiso flowchart:
This chart to take the most original process, Win10 own drawing software. Ha ha
request(config)
Source code axios.js/axios.js file
Promise uses its chain of uses to connect the request interceptor, the action that makes the request, the response interceptor, and the success or failure of our final request
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
* @return {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
// Axios.prototype.request.bind(context)
var instance = bind(Axios.prototype.request, context); // axios
// Copy axios.prototype to instance
// Copy the method from the Axios prototype object to instance: request()/get()/post()/put()/delete()
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
// Copy the properties from the Axios instance object to instance: the defaults and Interceptors properties
utils.extend(instance, context);
return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
axios.Axios = Axios;
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
Copy the code
/* Dispatch a request ** We use axios, which is the function returned by bind()@param {Object} config The config specific for this request (merged with this.defaults)
*/
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1) | | {}; config.url =arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
// Set config.method
if (config.method) {
config.method = config.method.toLowerCase();
} else if (this.defaults.method) {
config.method = this.defaults.method.toLowerCase();
} else {
config.method = 'get'; } -- -- -- -- -- -// Promise uses its chain of uses to connect the request interceptor, the action that makes the request, the response interceptor, and the success or failure of our thickest request
// Hook up interceptors middleware
// Undefined: the chain is a reject callback, which ensures that the interceptor will be called back in pairs
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
// Find all request interceptor functions. The last request interceptor is stored at the front of the array
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// The added response interceptor is stored after the array
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
// All request interceptors/request method/response interceptors are concatenated via promise's then()
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
// Return the promise that specifies our onResolved and onRejected
return promise;
};
Copy the code
dispatchRequest(config)
Source dispatchRequest. Js/default. Js file
/**
* Dispatch a request to the server using the configured adapter.
*
* @param {object} config The config that is to be used for the request
* @returns {Promise} The Promise to be fulfilled
*/
module.exports = function dispatchRequest(config) {
throwIfCancellationRequested(config);
// Ensure headers exist
config.headers = config.headers || {};
// Perform the necessary processing transformations on the data in config
// Set the content-type request header
// Transform request data
config.data = transformData(
config.data,
config.headers,
// Convert the data format
config.transformRequest // -- corresponds to the defalut file
);
// Flatten headers
// Consolidate all headers in config
config.headers = utils.merge(
config.headers.common || {},
config.headers[config.method] || {},
config.headers
);
utils.forEach(
['delete'.'get'.'head'.'post'.'put'.'patch'.'common'].function cleanHeaderConfig(method) {
deleteconfig.headers[method]; });var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
// Parse the unparsed data in response
// Json string parses into JS objects/arrays
response.data = transformData(
response.data,
response.headers,
// Convert the data format
config.transformResponse // -- corresponds to the defalut file
);
return response;
}, function onAdapterRejection(reason) {
if(! isCancel(reason)) { throwIfCancellationRequested(config);// Transform response data
if(reason && reason.response) { reason.response.data = transformData( reason.response.data, reason.response.headers, config.transformResponse ); }}return Promise.reject(reason);
});
};
Copy the code
// Get the request adapter corresponding to the current environment
adapter: getDefaultAdapter(),
// Request converter
transformRequest: [function transformRequest(data, headers) {
normalizeHeaderName(headers, 'Accept');
normalizeHeaderName(headers, 'Content-Type');
if (utils.isFormData(data) ||
utils.isArrayBuffer(data) ||
utils.isBuffer(data) ||
utils.isStream(data) ||
utils.isFile(data) ||
utils.isBlob(data)
) {
return data;
}
if (utils.isArrayBufferView(data)) {
return data.buffer;
}
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded; charset=utf-8');
return data.toString();
}
// If data is an object, specify the request body parameter format as JSON and convert the parameter data object to JSON
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json; charset=utf-8');
return JSON.stringify(data);
}
returndata; }].// Response data converter: parses string data
transformResponse: [function transformResponse(data) {
/*eslint no-param-reassign:0*/
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */}}returndata; }].Copy the code
xhrAdapter(config)
Source xhr.js file
// Create an XHR object
var request = new XMLHttpRequest();
// HTTP basic authentication
if (config.auth) {
var username = config.auth.username || ' ';
var password = unescape(encodeURIComponent(config.auth.password)) || ' ';
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
}
var fullPath = buildFullPath(config.baseURL, config.url);
// Initialize the request
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
// buildURL handles the request URL in the help folder buildurl.js
// Set the request timeout in MS
// Specify the timeout period
request.timeout = config.timeout;
// Listen for ready state
// bind a listener for request status changes
request.onreadystatechange = function handleLoad() {
if(! request || request.readyState ! = =4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
// will return status as 0 even though it's a successful request
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') = = =0)) {
return;
}
// Prepare the response
// Prepare the response object
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
varresponseData = ! config.responseType || config.responseType ==='text' ? request.responseText : request.response;
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request
};
// Determine the result state (success/failure) of the request promise based on the response status code
settle(resolve, reject, response); // settle. Js file below
// Clean up request
request = null;
};
// Handle browser request cancellation (as opposed to a manual cancellation)
// Bind request interrupt listener
request.onabort = function handleAbort() {
if(! request) {return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
// Clean up request
request = null;
};
// Not all browsers support upload events
// Bind the monitor of upload progress
if (typeof config.onUploadProgress === 'function' && request.upload) {
request.upload.addEventListener('progress', config.onUploadProgress);
}
// If cancelToken is configured
if (config.cancelToken) {
// Handle cancellation
// Specifies the callback function used to interrupt the request
config.cancelToken.promise.then(function onCanceled(cancel) {
if(! request) {return;
}
// Interrupt the request
request.abort();
// Make the request promise fail
reject(cancel);
// Clean up request
request = null;
});
}
if(! requestData) { requestData =null;
}
// Send the request
// Send a request, specifying the request body data, possibly null
request.send(requestData);
Copy the code
Settle. Js file
/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*/
module.exports = function settle(resolve, reject, response) {
var validateStatus = response.config.validateStatus;
if(! response.status || ! validateStatus || validateStatus(response.status)) {// The request succeeded
resolve(response);
} else {
// Request error
reject(createError( Createerror.js creates the error object function
'Request failed with status code ' + response.status,
response.config,
null, response.request, response )); }};default.js file// Read status code: [200,299]
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
}
Copy the code
5. What is axios request/response data converter?
function
1. Request converter: a function that performs specific processing on request header and request body data
// If data is an object, specify the request body parameter format as JSON and convert the parameter data object to JSON
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json; charset=utf-8');
return JSON.stringify(data);
}
Copy the code
2. Response converter: A function that parses the response body JSON string into A JS object or array
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */}}Copy the code
6. Overall structure of Response
{
data,
status,
statusText,
headers,
config,
request
};
// Corresponds to xhr.js in the adapters folder
Copy the code
7. Error overall structure
{
config,
request,
response,
...
}
// enhanceerror.js corresponds to the source core folder
Copy the code
8. How do I cancel an outstanding request?
1. When the cancelToken object is configured, save the cancel function
(1) Create a cancelPromise for future interrupt requests
(2) And define a cancel function to cancel the request
(3) Pass the cancel function
2. Call Cancel () to cancel the request
(1) Execute cancel function to pass error message message
(2) Internally the cancelPromise will be made a success, and the success value is a Cancel object
(3) Interrupt the request in the successful callback of cancelPromise and let the promise fail. The reason for the failure is the Cancel object
Canceltoken.js/xhr.js
function CancelToken(executor) {
if (typeofexecutor ! = ='function') {
throw new TypeError('executor must be a function.');
}
// Prepare a Promise object for the cancellation request, and save the resolve function to the outside.
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
// Save the current token object
var token = this;
// The executor function is externally defined and internally called
// Execute the received executor function immediately, passing in the cancel function to cancel the request
// The cancel function is internally defined, externally called - "combined with the above (Axios understands using point 6 together with Kangkang)
executor(function cancel(message) {
// If there is a reason in the token, the request has been cancelled. | see, after this if see the token below. The first reason
if (token.reason) {
// Cancellation has already been requested
return;
}
// Specify the token's reason as a Canel object
token.reason = new Cancel(message);
// Specify the promise of the cancellation request as success with a value of reason
resolvePromise(token.reason);
});
}
Copy the code
// If cancelToken is configured
if (config.cancelToken) {
// Handle cancellation
// Specifies the callback function used to interrupt the request
config.cancelToken.promise.then(function onCanceled(cancel) {
if(! request) {// If the request is not finished, you can follow the interrupt request
// If the request is complete, return directly, unable to interrupt the following sequence of operations
return;
}
// Interrupt the request
request.abort();
// Make the request promise fail
reject(cancel);
// Clean up request
request = null;
});
}
Copy the code
— — — — — — — — — — — — — — — — — — — — — — — –
conclusion
If you are interested in the above code, clone my code on gitHub and send kohane a chicken leg (like, comment, STRT) if you think it will help you
Github has more content than this article, so don’t miss it.