1. Understanding and using axios
1.1 What is Axios?
- The most popular ajax request library on the front end
- React/Vue officially recommends using Axios to make Ajax requests
- Documents: github.com/axios/axios
1.2 Features of AXIos
- Asynchronous Ajax request library based on XHR + Promise
- It can be used on either the browser side or the Node side
- Support for request/response interceptors
- Support request cancellation
- Request/response data transformation
- 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
-
A new AXIOS is created based on the specified configuration, so each new AXIOS has its own configuration
-
The new Axios just doesn’t have a way to cancel requests or batch them, and everything else is the same syntax
-
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:
-
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
-
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
-
Syntactically: Axios is not an instance of Axios
-
Functionally: Axios is an instance of Axios (Axios owns methods on axios instance objects)
-
Axios is the function returned by axios.prototype. request function bind()
-
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?
-
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
-
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?
-
Request(config) ==> dispatchRequest(config) ==> xhrAdapter(config)
-
Request(config): Link request interceptors/dispatchRequest()/response interceptors via the Promise chain to return a promise
-
DispatchRequest (config): Convert request data → call xhrAdapter() to send a request → convert response data after the request returns. Return to the promise
-
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?
-
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
-
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
- 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
- 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?
-
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
-
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