1. Understanding and using axios

1.1 What is Axios?

  1. The most popular ajax request library on the front end
  2. React/Vue officially recommends using Axios to make Ajax requests
  3. Documents: github.com/axios/axios

1.2 Features of AXIos

  1. Asynchronous Ajax request library based on XHR + Promise
  2. It can be used on either the browser side or the Node side
  3. Support for request/response interceptors
  4. Support request cancellation
  5. Request/response data transformation
  6. Send multiple requests in batches

1.3 Axios Common syntax

  • Axios (config) : The usual/essential way to send any type of request
  • Axios (url,config) : You can specify only the URL to send get requests
  • Axios.request (config) : equivalent to sending axios(config)
  • Axios.get (url[,config]) :
  • Axiod. delete(url[,config]) : sends a DELETE request
  • Axios. post(URL [,data,config]) : sends a POST request
  • Axios. put(URL [,data,config]) : sends a PUT request
  • Axios.defaults. XXX: The default global configuration of the request

  • Axios. Interceptors. Request. Use () : add request interceptor
  • Axios. Interceptors. Response. Use () : add response interceptors
 <script>
        //Promise
        // Set the request interceptor config configuration object
        axios.interceptors.request.use((config) = > {
            console.log('Request interceptor success # 1');
            
            // Failure condition
            // throw 'argument is wrong'
            // Modify the parameters in config
            
            config.params = {a:100};

            return config;
        },(error) = > {
            console.log('Request interceptor failed # 1');
            return Promise.reject(error)
        });

        axios.interceptors.request.use((config) = > {
            console.log('Request interceptor success number two');
            
            // Failure condition
            // throw 'argument is wrong'
            // Modify the config parameters
            config.timeout = 2000;
            return config;
            },(error) = > {
                console.log('Interceptor request failed - Number two');
                return Promise.reject(error);
            });

        // Set the response interceptor
        axios.interceptors.response.use((response) = > {
            console.log('Response interceptor success no. 1');
            // return response.data;
            return response;
        }, function (error) {
            console.log('Response interceptor failure No. 1')
            return Promise.reject(error);
        });
            
        axios.interceptors.response.use((response) = > {
            console.log('Response interceptor success number two');
            return response;   
        },(error) = > {
            console.log('Response interceptor failure No. 2');
            return Promise.reject(error)
            
        });

        // Send the request
        axios({
            method:'GET'.url:'http://localhost:3000/posts'
        }).then(response= >{
            console.log('Results of successful custom callback processing');
            console.log(response);
            
        }).catch(reason= >{
            console.log('Custom failure callback');
            
        })


    </script>
Copy the code

The interceptors are all successful

Request interceptor 1 throws an error

Request interceptor 2 throws an error


  • Axios.create ([config]) : Creates a new AXIos. The advantage is that you can configure different default configurations for easy use

    // Create instance object /getJoke
            const joke = axios.create({
                baseURL:'https://api.apiopen.top'.timeout:2000
            })
    
            // Create another instance object
            const another = axios.create({
                baseURL: 'https://b.com'.timeout: 2000
            });
    Copy the code
  1. A new AXIOS is created based on the specified configuration, so each new AXIOS has its own configuration

  2. The new Axios just doesn’t have a way to cancel requests or batch them, and everything else is the same syntax

  3. Why was this syntax designed?

(1) Requirements: The configuration required by some interfaces in the project is different from that required by other interfaces. How to deal with it?

(2) Solution: Create two new AXIos, each with its own unique configuration, to be applied to interface requests with different requirements

Note: It does not have the following features


  • Axios.cancel () : Used to create an error object to Cancel the request
  • Axiod.canceltoken () : The token object used to create the cancellation request
  • Axios.iscancel () : Whether it was an error to cancel the request
  • Axios.all (promise) : Used to batch execute multiple asynchronous requests
  • Axios.spread () : Method used to specify the callback function that receives all success data

Cancel request:

  1. The basic flow

    Configure the cancelToken object

    Caches the cancel function used to cancel the request

    Call the cancel function at a later specific time to cancel the request

    In the error callback, determine if error is Cancel and respond

  2. Realize the function

    Click the button to cancel a request in progress

    Before requesting an interface, cancel a previous incomplete request

<script>
        // Get the button
        const btns = document.querySelectorAll('button');
        //2. Declare global variables
        let cancel = null;
        // Send the request
        btns[0].onclick = function(){
            // Check whether the last request was completed
            if(cancel ! = =null) {// Cancel the previous request
                cancel();
            }
            axios({
                method: 'GET'.url: 'http://localhost:3000/posts'.//1. Add attributes of the configuration object
                cancelToken: new axios.CancelToken(function(c){
                    //3. Assign the value of c to cancel
                    cancel = c;
                })
            }).then(response= > {
                console.log(response);
                // Initialize the value of cancel
                cancel = null;
            }).catch((reason) = > {
                console.log('Request cancellation'); })}// Bind the second event cancellation request
        btns[1].onclick = function(){
            cancel();
        }
    </script> 
Copy the code

2 Axios source code analysis

2.1 Source directory structure

2.2 Source Code Analysis

2.2.1 Relationship between AXIos and AXIos

  1. Syntactically: Axios is not an instance of Axios

  2. Functionally: Axios is an instance of Axios (Axios owns methods on axios instance objects)

  3. Axios is the function returned by axios.prototype. request function bind()

  4. Axios, as an object, has all the methods on the Axios prototype object, has all the properties of the Axios object

2.2.2 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 properties: defaults/ Interceptors

  2. Different:

    (1) The default configuration is likely to be different

    (2) Instance does not have some methods added after axios: create()/ CancelToken()/ all()

2.2.3 Execution sequence of response interceptors

This section starts with the 1.3 interceptor code and results

The key source for this step is as follows:

Because two of the chain arrays are fetched at a time, a undefined is added as a placeholder

  • In general, the real call (dispatchRequest) is placed in the middle, undefined space is placed, the request header is inserted, and the response is placed at the end

The execution sequence is as follows:

  • All interceptors are successfully executed in sequence

  • Request interceptor # 2 to throw exceptions in order of execution

Other things are similar

2.2.4 The overall process of AXIOS?

  1. Request(config) ==> dispatchRequest(config) ==> xhrAdapter(config)

  2. Request(config): Link request interceptors/dispatchRequest()/response interceptors via the Promise chain to return a promise

  3. DispatchRequest (config): Convert request data → call xhrAdapter() to send a request → convert response data after the request returns. Return to the promise

  4. XhrAdapter (config): Creates an XHR object, sets it according to config, sends a specific request, receives the response data, and returns a promise

2.2.5 What is axios request/response interceptor?

  1. Request interceptor:

    A callback function executed before the request is actually sent

    Requests can be checked or configured for specific processing

    The successful callback function is passed config by default (it must be)

    Failed callback functions are passed error by default

  2. Response interceptor

    A callback function that is executed after a request has received a response

    Specific processing of the response data is possible

    The successful callback function passes response by default

    Failed callback functions are passed error by default

2.2.6. What is axios request/response data converter?

This part of the function can be done by interceptors

  1. Request converter: A function that performs specific processing on request header and request body data
if (utils.isObject(data)) {
 setContentTypeIfUnset(headers, 'application/json; charset=utf-8');
 return JSON.stringify(data);
}
Copy the code
  1. Response converter: A function that parses the response body JSON string into a JS object or array
response.data = JSON.parse(response.data)
Copy the code

2.2.7 Overall structure of Response

{
 data,
 status,
 statusText,
 headers,
 config,
 request
 }
Copy the code

2.2.8 Overall structure of Error

{
	message,
	response,
	request
}

Copy the code

2.2.9 How Do I Cancel an Outstanding Request?

  1. When the cancelToken object is configured, the cancel function is saved

    (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 cacel function and pass in error 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 proimse that made the request fail. The reason for the failure is the Cancel object

3 Simulation code

3.1 Simulate sending request code

 <script>
        //axios sends the request axios. Prototype. request bind
        //1. Declare the constructor
        function Axios(config){
            this.config = config;
        }

        Axios.prototype.request = function(config){
            // Send the request
            // Do some merge work, but no merge is needed here
            // Create a Promise object
            let promise = Promise.resolve(config);
            // console.log(promise);
            // Declare an array
            let chains = [dispatchRequest,undefined];/ / undefined placeholders
            // Call the then method to specify the callback
            let result = promise.then(chains[0],chains[1]);
            // Return the result of the promise
            return result;
        }

        / / 2. DispatchRequest function
        function dispatchRequest(config){
            // Call the adapter to send the request
            return xhrAdapter(config).then(response= >{
                // Convert the result of the response
                / /...
               return response;
                
            },error= >{
                throwerror; })}/ / 3. Adapter Adapter
        function xhrAdapter(config){
            console.log('xhrAdapter function execution ');
            return new Promise((resolve,reject) = > {
                /* Send ajax requests */
                // Create an object
                let xhr = new XMLHttpRequest();
                / / initialization
                xhr.open(config.method,config.url)
                / / send
                xhr.send();
                // Bind events
                xhr.onreadystatechange = () = > {
                    if(xhr.readyState === 4) {if (xhr.status>=200 && xhr.status<300) {
                            // Successful status
                            resolve({
                                // Configure objects
                                config:config,
                                / / response body
                                data:xhr.data,
                                / / response headers
                                header: xhr.getAllResponseHeaders(), / / string
                                // XHR request object
                                request: xhr,
                                // Response status code
                                status:xhr.status,
                                // Response status string
                                statusText:xhr.statusText

                            });
                            
                        }else{
                            // Failed state
                            reject(new Error('Request failed status code is' + xhr.status))
                        }
                    }
                    
                }
                
            })
            
        }

        // create the axios function
         let axios = Axios.prototype.request.bind(null);
        axios({
            method:'GET'.url:'http://localhost:3000/posts'
        }).then(response= > {
            console.log(response);
        });
    </script>
Copy the code

3.2 Simulate interceptors

<script>
       // constructor
       function Axios(config){
           this.config = config;
           this.interceptors = {
               request:new InterceptorManager(),
               response:new InterceptorManager(),
           }
       }
       // Send the request difficult and important points
       Axios.prototype.request = function(config){

        // Create a Promise object
        let promise = Promise.resolve(config);
        // Create an array
        let chains = [dispatchRequest,undefined];
        // Handle interceptors
        Request. Handles = []
       this.interceptors.request.handlers.forEach( item= >{
           chains.unshift(item.fulfilled,item.rejected)
       });
       Request. Handles = []
       this.interceptors.response.handlers.forEach( item= >{
           chains.push(item.fulfilled,item.rejected)
       });
    // console.log(chains);
       while(chains.length > 0){
           promise = promise.then(chains.shift(),chains.shift());
       }
       return promise
     
       }
       // Send the request
       function dispatchRequest(config) {
           // Return a Promise object
           return new Promise((resolve,reject) = > {
               resolve({
                   status:200.statusText:'OK'})})}// Create an instance
       let context = new Axios({})
        // Create the axios function
        let axios = Axios.prototype.request.bind(context);

       // Add the context attribute to the axios function object
       Object.keys(context).forEach(key= >{
           axios[key] = context[key];
       })
       // Interceptor manager constructor, used to save the callback
       function InterceptorManager(){
           this.handlers = [];
       }

       InterceptorManager.prototype.use = function (fulfilled,rejected) {
           this.handlers.push({
               fulfilled,
               rejected
           })
       }
       
       
        // The following is the functional test code
        // Set the request interceptor config configuration object
        axios.interceptors.request.use(function one(config) {
            console.log('Request for interceptor successful - Number one');
            return config;
        }, function one(error) {
            console.log('Interceptor request failed - Number 1');
            return Promise.reject(error);
        });

        axios.interceptors.request.use(function two(config) {
            console.log(Request for interceptor successful - Number two.);
            return config;
        }, function two(error) {
            console.log('Interceptor request failed - Number two');
            return Promise.reject(error);
        });

        // Set the response interceptor
        axios.interceptors.response.use(function (response) {
            console.log('Response interceptor success no. 1');
            return response;
        }, function (error) {
            console.log('Response interceptor failure No. 1')
            return Promise.reject(error);
        });

        axios.interceptors.response.use(function (response) {
            console.log('Response interceptor success number two')
            return response;
        }, function (error) {
            console.log('Response interceptor failure No. 2')
            return Promise.reject(error);
        });


        // Send the request
        axios({
            method: 'GET'.url: 'http://localhost:3000/posts'
        }).then(response= > {
            console.log(response);
        });
    </script>
Copy the code

3.3 Simulating a cancellation request

<body>
    <div class="container">
        <h2 class="page-header">Axios cancels the request</h2>
        <button class="btn btn-primary">Send the request</button>
        <button class="btn btn-warning">Cancel the request</button>
    </div>
    <script>
        // constructor
        function Axios(config){
            this.config = config;
        }
        // Prototype request method
        Axios.prototype.request = function(config){
            return dispatchRequest(config);
        }
        function dispatchRequest(config){
            return xhrAdapter(config)
        }
        //xhrAdapter
        function xhrAdapter(config){
            // Send an Ajax request
            return new Promise((resolve,reject) = > {
                // instantiate the object
                const xhr = new XMLHttpRequest();
                / / initialization
                xhr.open(config.method,config.url);
                / / send
                xhr.send();
                // Process the result
                xhr.onreadystatechange = () = > {
                    // Determine the result
                    if (xhr.readyState===4) {
                        if (xhr.status>=200 && xhr.status<300) {
                            // Set the status successfully
                            resolve({
                                status:xhr.status,
                                statusText:xhr.statusText
                            })
                            
                        }else{
                            reject(new Error('Request failed'))}}}// About the processing of the cancellation request
                if (config.cancelToken) { // If config has cancelToken
                    // Specify a successful callback to the Promise object on the cancelToken object
                    config.cancelToken.promise.then(value= >{
                        xhr.abort();
                        // Set the overall result to failure
                       // reject(new Error(' request has been cancelled '))})}})}// Create the axios function
        const context = new Axios({})
        const axios = Axios.prototype.request.bind(context);
        //CancelToken constructor
        function CancelToken(executor){
            // Declare a variable
            var resolvedPromise
            // Add attributes to the instance object
            this.promise = new Promise((resolve) = >{
                // Assign resolve to resolvePromise
                resolvedPromise=resolve; // make resolvePromise and resolve the same
            });
        // Call the executor function
        executor(function(){
            // Execute the resolvePromise functionresolvedPromise(); })}// Get the code above for the simulation implementation
        const btns = document.querySelectorAll('button');
        //2. Declare global variables
        let cancel = null;
        // Send the request
        btns[0].onclick = function(){
            // Check whether the last request was completed
            if(cancel ! = =null) {// Cancel the previous request
                cancel();
            }

            // Create a cancelToken value
            let cancelToken = new CancelToken(function(c){
                cancel = c;
            });

            axios({
                method: 'GET'.url: 'http://localhost:3000/posts'.//1. Add attributes of the configuration object
                cancelToken: cancelToken
            }).then(response= > {
                console.log(response);
                // Initialize the value of cancel
                cancel = null; })}// Bind the second event cancellation request
        btns[1].onclick = function(){
            cancel();
        }
    </script>   
</body>
Copy the code

4 reference

Reference video: Axios Video from Silicon Valley

5 code

Making the address