One, foreword

Characteristics of 1.

  • Ajax requests are sent to the server via axiOS on the browser side.
  • Send HTTP requests to the server using AXIOS in NodeJS
  • Supporting Promise

2. Use

In a project, NPM and YARN are used to install dependencies. In general exercises, just use the script tag.

If the response is too slow, use BootCDN to use the resource

www.bootcdn.cn/

  • Links about requests

Using a mock or JSON-server to simulate interface data is a good way to practice

  • About debugging

Node_modules /axios/dist/mine-axios.js on gitee is packaged and imported directly from script for debugging

  • Source code analysis

Node_modules /axios/lib

Two, basic use

You can use the AXIos base method to send a request, or you can use its methods

1. Axios ()

  • The axios({url,config}) function receives an object containing the request address and related parameters.
  • Return a Promise object
Axios ({method: 'GET', url: 'http://localhost:3000/posts/3', / / set the request body data: {}}), then (res = > {the console. The log (res)})Copy the code

For more information on how to use it, see the documentation on the Axios website

2. Configure object resolution

  • url

Specifies the address requested, required

  • method

Specifies the method of the request. If method is not specified, the request defaults to get

  • baseURL

Set up the infrastructure for the request link, which is combined with the URL

  • data

The data sent as the request body is applicable to the post, PUT, and patch request methods

  • timeout

Specifies the number of milliseconds for the request to timeout, if longer than the specified time, the request will be interrupted

  • transformRequest

Allows request data to be modified before being sent to the server. Can only be used in post, PUT, and patch request methods.

TransformRequest: [function (data) {// Return data;}],Copy the code

** Note: Functions in the ** array must return a string /ArrayBuffer/Stream

  • transformResponse

Response data is allowed to be modified before it is passed to then/catch

  • headers

Custom request header, which is an object

  • params

The URL parameter sent with the request must be an unformatted object

params:{
  ID:12345
}
Copy the code

3. Default Settings

To facilitate each request, you can set a default configuration for AXIos

Axios. defaults sets the default configuration with related default arguments

axios.defaults.method = 'GET'
Copy the code

4. Create an instance object to send the request

The request is sent by creating an instance object with axios.create()

const obj = axios.create({
	baseURL:'',
	methods:'GET'
})
obj({
	url:''
})
.then(response=>{

})

Copy the code

5. Axios interceptors

  • The basic use

Interceptor notes are mainly functions that fall into two broad categories (request and response interceptors).

Request interceptor: Its main job is to do something with the callback function before the request is sent

Response interceptor: Uses callback functions to process data before it is received by then and catch

The e two main callback functions in the interceptor (success and failure callback)—- are related to promise. If the interceptor calls a failed callback, as in the example below, it returns the Promise of the Rejected state

The successful callback function parameter config: in the request interceptor indicates that we can make changes to the request parameter configuration object.

Response: It is the default return result of the AXIos request

/ / 1. Add request blocker axios. Interceptors. Request. Use (function (config) {/ / what to do before sending a request return}, Return promise.reject (error); return promise.reject (error); }); / / 2. Add the response blocker axios. Interceptors. Response. Use (function (response) {/ / to do something about the response data return}, Return promise.reject (error); return promise.reject (error); });Copy the code
  • Data processing sequence

In an AXIOS request with an interceptor, the data first passes through the request interceptor — > response interceptor — >then/ Catch

  • Multiple interceptors execute in order

Multiple request interceptors: Those defined last are executed first

Multiple response interceptors: Those defined first are executed first

See axios source code analysis for specific reasons

6. Cancel the request

//2. Declare global variable let cancel = null; CancelToken :new axios. cancelToken (function(c){//3. Assign c to cancel cancel = c})}) //4. Cancel ()Copy the code

Axios request response structure

  • config

Contains configuration information about the request

  • data

Contains the result of the server response

  • headers

The header information for the response

  • request

Native Ajax request object – XMLHttpRequest object

  • status

The HTTP status code of the server response

  • statusText

HTTP status information for the server response

4. Source code analysis of AXIOS

Directory File Analysis

Detailed source code analysis, file functions are annotated in the source code

Axios creation process

You can see the creation of axios in the source code axios.js.

var axios = createInstance(defaulyts)
Copy the code

The createInstance(defaults) function in axios.js

function createInstance(defaultConfig) { //1.Axios.js var context = new Axios(defaultConfig); //2.bind var instance = bind(Axios.prototype.request, context); //3. Extend (instance, axios.prototype, context); utils.extend(instance, context); return instance; }Copy the code
1. Axios.js
   var context = new Axios(defaultConfig);

Copy the code

This line of code needs to be traced back to axios.js

function Axios(instanceConfig) { this.defaults = instanceConfig; this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager() }; } Axios.prototype.request = function request(config) { //... }; Axios.prototype.getUri = function getUri(config) { //... }; . // Add more methods to the prototypeCopy the code

The main points to note in the above code are the following

  • Set defaults to configure default objects
  • Set interceptors to add request/response interceptors

This corresponds exactly to the setup scheme in the previous interception

axios.interceptors.request.use()
axios.interceptors.response.use()

Copy the code
  • Add methods to the Axios prototype object

On the axios instantiation object you can call the axios.request and many other methods we used before

So that’s why when we use Axios, we can either use it directly or we can use it by calling the related methods, right

** In summary: ** Objects instantiated in this step can call methods to send requests and so on, but not directly as usual. Hence the next steps

2.bind
var instance = bind(Axios.prototype.request, context);

Copy the code

Bind is a binding function, wrapped in the source code, that refers this to the context

The instance here is consistent with the axios.prototype. request code; it is a function

3. Copy
 utils.extend(instance, Axios.prototype, context);
 utils.extend(instance, context);

Copy the code

The previous instance was just a function.

The extend method here adds both axios. prototype and the method that instantiates the context object to instance.

After this step,

  1. Instance is a function
  2. As objects, there are many methods
4. Simulation implementation

The creation process was briefly described in the above process, but the creation process of the mock implementation will be a little clearer next

Function Axios(config) {this. Defaults = config; this.interceptors = { request:{}, Axios.prototype.request = function (config) {console.log(config)} axios.prototype. get = Function (config) {// Call the request method to return this.request(config); } axios.prototype. post = function (config) {// call request to return this.request(config); } function createInstance(config) {//1. Let context = new Axios(config); / / cannot be used as a function / / 2. Create request function let the instance = Axios. Prototype. Request. Bind (context); // copy the method (make instance an Object) object.keys (axios.prototype).foreach (key=>{instance[key] = Axios.prototype[key].bind(context); // Note that we need to bind to the context, this points to always point to context}) //4. Add default Settings (defaults and Interceptors) object.keys (context).foreach (key=>{instance[key] = context[key]; }) return instance; } var axios = createInstance({method:'get'}) axios({method:'post'}) axios.get({data:'beatrix'})Copy the code

Axios request process

From the above analysis of the axios creation process, I believe it is clear that the call to AXIos is essentially the call to axios.prototype. request, including other prototype object methods are based on request method, so the next concrete analysis of axios request process

axios({

}).then(res=>{

})

Copy the code
1.request
Axios.prototype.request = function request(config) { //1. Check the parameters passed the if (typeof config = = = 'string') {config = the arguments [1] | | {}; config.url = arguments[0]; } else { config = config || {}; } //2. MergeConfig (this.defaults, config); / / 3. The request method to judge the if (config. Method) {config) method = config) method. The toLowerCase (); } else if (this.defaults.method) { config.method = this.defaults.method.toLowerCase(); } else { config.method = 'get'; Var chain = [dispatchRequest, undefined]; Var promise = promise.resolve (config); / / 6. Traversal request interceptor and the interceptor enclosing interceptors. Request. ForEach (function unshiftRequestInterceptors (interceptor) { chain.unshift(interceptor.fulfilled, interceptor.rejected); }); this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { chain.push(interceptor.fulfilled, interceptor.rejected); }); While (chain.length) {promise = promise.then(chain.shift(), chain.shift()); } // return a promise; };Copy the code

In step 4, dispatchRequst is a function that sends the request, using it to call HTTP, XMLHttprequest.

In step 7, it will be executed as the promise’s success callback function

2. dispatchRequest.js
var chain = [dispatchRequest, undefined];

Copy the code

In dispatchRequest, the following things are done

function dispatchRequest(config) { //1. To ensure that the header information exists config. Headers = config. Headers | | {}; Config. data = transformData(config.data, config.headers, config.transformRequest); / / 3. Merge all other header configuration items config. The headers = utils. Merge (config.headers.com mon | | {}, config. The headers/config. Method | | {}, config.headers ); ForEach (['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], function cleanHeaderConfig(method) { delete config.headers[method]; }); XHR var / / 5. Get the adapter object HTTP adapter = config. The adapter | | defaults. The adapter. //6. HTTP return Adapter (config). Then (function onAdapterResolution(response) { throwIfCancellationRequested(config); // Transform response data response.data = transformData( response.data, response.headers, config.transformResponse ); Return response; // Set the promise success value to the response result. }, 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); return promise.reject (reason); }); };Copy the code

** Note that ** the dispatchRequest function returns a result based on the promise.then return (i.e., it returns a promise object).

3.xhr.js

In step 6 above, in the action of sending the request

return adapter(config).then(function onAdapterResolution(response) {
     
    }, function onAdapterRejection(reason) {
        
});


Copy the code

In the adpter function above, the xhrAdapter function in xhr.js is called, which sends an Ajax request and returns a Promise object

4. Summary

/ / call axios.prototype. Request (dispatchRequest) / / call xhrAdapter (dispatchRequest) / / call xhrAdapter (dispatchRequest) / / Axios also completes, returning a Promise object

If you’re not familiar with this, I suggest you read the source code analysis, which explains it in detail. Since the AXIos request process involves a lot of promise use, I suggest you read promises several times

5. Simulation implementation

Simulation implementation, is the function of the above shorthand, only the core structure, if the above is not very understand, see this should be ok.

Function Axios(config) {this. Defaults = config; this.interceptors = { request:{}, response:{} } } //1. Request = function (config) {// create a promise object let promise = promise.resolve (config); / / declare an array let chains = [dispatchRequest, undefined]; Let result = promise. Then (Chains [0], Chains [1]); // Perform the first callback // Return result; } // dispatchRequest function dispatchRequest(config) {return xhrAdapter(config). Then (response=>{return Error =>{throw error})} //3.adapter adapter function xhrAdapter(config) {console.log('xhrAdapter function execution '); Return new Promise((resolve,reject)=>{// Send ajax request let XHR = new XMLHttpRequest(); // initialize xhr.open(config.method,config.url); / / XHR. The send (); Xhr.onreadystatechange =function(){if(xhr.readyState==4){if(xhr.status==200){resolve({// Finally return the request result config:config, data:xhr.response, //.... }); }else{reject(' request failed ')}}}})} //4. Create axios let axios = axios. Prototype. Request. Bind (null) / / 5. Use axios({method:'GET', URL :' HTTP :/localhost:3000'}).then(response=>{console.log(response))Copy the code

Axios interceptor

Let’s start with interceptor execution:

Axios. Interceptors. Request. Use (function (config) {/ / what to do before sending a request return}, Return promise.reject (error); return promise.reject (error); });Copy the code
  • Interceptors properties

Remember that during the creation of axios, the axios constructor initializes this property, which contains two properties (request and Response),

function Axios(instanceConfig) {
    this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
    };
}

Copy the code
1.InterceptorManager

Here is the InterceptorManager constructor

Function InterceptorManager() {// Create a new attribute this.handlers = []; } InterceptorManager.prototype.use = function use(fulfilled, rejected) { this.handlers.push({ fulfilled: fulfilled, rejected: rejected }); return this.handlers.length - 1; };Copy the code

With the Use method, the handlers above have a value (an object), which is the callback we passed in using the Use method

2. Execution sequence

The order of execution of multiple interceptors has not been resolved before, and is now addressed here

/ / the first axios. Interceptors. Request. Use (function one (res) {the console. The log (" request interceptor success 1 ")}, function one (err) { The console. The log (" request interceptor failure 1 ")}) / / second step axios. Interceptors. Request. Use (function two (res) {the console. The log (" request interceptor success 2 ")}, function Two (err) {the console. The log (" 2 "request interceptor failure)}) / / step 3 axios. Interceptors. Response. Use (function one (res) {the console. The log (" response interceptor success 1") {}, function one (err). The console log (" response interceptor failure 1 ")}) / / step 4 axios. Interceptors. Response. Use (function two (res) { Console. log(" response interceptor failed 2")},function two(err) {console.log(" response interceptor failed 2")}) axios({method:'GET', url:'http://localhost:3000' }).then(res=>{ console.log(res) })Copy the code

Let’s look at the execution order:

  1. After the first step, there are attributes on the Request object: an array object containing two callback functions, one

  1. After the second, third and fourth steps are done, there are handlers on request and Response [{one},{two}]

  1. Axios starts sending the request, enters the request function in the request process, and iterates through the request interceptor
Var chain = [dispatchRequest, undefined]; Var promise = promise.resolve (config); / / 6. Traversal request interceptor and the interceptor enclosing interceptors. Request. ForEach (function unshiftRequestInterceptors (interceptor) { chain.unshift(interceptor.fulfilled, interceptor.rejected); });Copy the code

After unshift, the two callbacks (success/failure) from each object in the Handlers object array are pushed into the chain, which looks like this:

  1. Add the result of the chain array to the method in the response interceptor through the push method
/ / traverse response interceptor enclosing interceptors. Response. ForEach (function pushResponseInterceptors (interceptor) { chain.push(interceptor.fulfilled, interceptor.rejected); });Copy the code

  1. These callbacks are then retrieved and executed using the Shift method

Shift alters the array, so the successful and failed callbacks are pulled out, traversing the chain array, returning a promise result in axios.rototype.request, and leaving the rest to Axios ().then

Then (chain.shift(), chain.shift()); then(chain.shift(), chain.shift()); } return promise;Copy the code
3. Simulation implementation
/ / 1. Axios. The function prototype. Request method Axios (config) {/ / initializes the enclosing defaults = config enclosing interceptors = {request: new InterceptorManager(), response: new InterceptorManager(), Prototype = function (config) {// create a promise object let promise = promise.resolve (config); / / create an array of chains const chains = [dispatchRequest, undefined]; / / processing / / request interceptor interceptors in front of chains enclosing interceptors. Request. Handlers. ForEach (item = > { chains.unshift(item.fulfilled,item.rejected); }) / / response interceptors on chains behind this. Interceptors. Response. Handlers. ForEach (item = > {chains. Push (item. Fulfilled, item. The rejected); }) while(chains. Length >0){promise = promise.then(chains. Shift (),chains. Function dispatchRequest() {return new Promise(resolve,reject)=>{resolve({status:200, })})} / /. 3. Build axios / / create an instance context = new axios ({}) / / create axios function let axios = axios. Prototype. Request. Bind (context); Keys (context).foreach (key=>{axios[key] = context[key]}) //4 Interceptors manager constructor function InterceptorManager () {enclosing handlers = []} InterceptorManager. Prototype. Use = function (fulfilled, rejected) { this.handlers.push({ fulfilled, rejected, }) } //.5. Set the request/response interceptor axios. Interceptors. Request. Use (function one (res) {the console. The log (" request interceptor success 1 ")}, function one (err) { The console. The log (" request interceptor failure 1 ")}) axios. Interceptors. Request. Use (function two (res) {the console. The log (" request interceptor success 2 ")}, function Two (err) {the console. The log (" 2 "request interceptor failure)}) axios. Interceptors. Response. Use (function one (res) {the console. The log (" response interceptor success 1") {}, function one (err). The console log (" response interceptor failure 1 ")}) axios. Interceptors. Response. Use (function two (res) { Console. log(" response interceptor failed 2")},function two(err) {console.log(" response interceptor failed 2")}) //6. Using axios ({method: 'GET'})Copy the code