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,
- Instance is a function
- 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:
- After the first step, there are attributes on the Request object: an array object containing two callback functions, one
- After the second, third and fourth steps are done, there are handlers on request and Response [{one},{two}]
- 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:
- 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
- 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