preface

Hello, I’m Zhou. I was only interested in how to use Axios interceptor, but recently I looked at the source code of Axios interceptor, and I had a sense of enlightenment.

What is an interceptor

Interceptors, as the name implies, intercept requests. Axios has two types of interceptors, request interceptors and response interceptors. Once an interceptor is added to an Axios instance, each API request will execute the interceptor. Execution order: Request interceptor > API request > response interceptor. Use as follows

/ / add request interceptor axios. Interceptors. Request. Use (function (config) {/ / what to do before sending a request return config. }, function (error) {return promise.reject (error); }); / / add the response interceptor axios. Interceptors. Response. Use (function (response) {/ / do something to return the response to the response data; }, function (error) {return promise.reject (error); });Copy the code

The interceptor can also be cancelled. The Axios interceptor provides the eject method to cancel the interception function (eject takes an ID as an argument, and id is the return value of the use function).

const interceptorId = axios.interceptors.request.use(function () {/*... * /}); axios.interceptors.request.eject(interceptorId);Copy the code

The purpose of the Axios interceptor

Collecting Request Time

Sometimes we need to count the time it takes for an API to send a request to return data. This kind of centralized logic is suitable for interceptors, and it is very easy to change the process in the future.

Axios. Interceptors. Request. Use ((config) = > {/ / the starting time of the API request config. Metadata = {startTime: new Date ()} return config. }); Axios. Interceptors. Response. Use ((res) = > {/ res/API request of the end of the time. The config. The metadata. The endTime = new Date () const {startTime, EndTime} = res.config.metadata // Calculate the time that the request takes console.log(endtime-startTime) return res});Copy the code

The response interceptor intercepts the back-end status code

Intercept the response status code, return the 404 status code to the back end, jump to the 404 page, can also do other status code judgment (not listed here)

axios.interceptors.response.use((res) => {
  return res
}, err => {
  if (err.response.status === 404) {
    router.replace({
      path: '/404.html'
    })
  }
})

Copy the code

The idea of interceptors

At first, many friends (my own 🐶) will be interceptor this lofty noun tiger live, think that the principle behind the lofty noun is unfathomable. No, all you need to know about interceptors is simple array manipulation. Now let’s rearrange the request interceptor before the API request and the response interceptor after the API request. If you think about it 🤔, they are essentially just an order of execution. This is actually an array chain can be implemented, the request interceptor function in front of the array, THE API request in the middle, the response interceptor behind the array, traversing the array chain implementation of the interceptor execution order, is not very simple 😄.

Interceptor source code

The InterceptorManager constructor has a Handlers array that holds all interceptors and adds three methods to its prototype, use for adding interceptors and returning an ID, eject for canceling interceptors and forEach for iterating through all interceptors.

Function InterceptorManager() {// Hold an array of interceptors, axios.interceptors. Use interceptors are pushed to the handlers, You can add multiple interceptors this.Handlers = []; } // Mount the use method on the interceptor prototype, push an object into the handler array, return an ID, and cancel the interceptor function with eject(id). InterceptorManager.prototype.use = function use(fulfilled, rejected, options) { this.handlers.push({ fulfilled: fulfilled, rejected: rejected, synchronous: options ? options.synchronous : false, runWhen: options ? options.runWhen : null }); return this.handlers.length - 1; }; / / remove the interceptor InterceptorManager. Prototype. Eject = function eject (id) {/ / by id to find the corresponding interceptors, Handlers [id]) {handlers[id] = null; }}; / / traverse perform all interceptor InterceptorManager. Prototype. ForEach = function forEach (fn) {utils. ForEach (enclosing handlers, function forEachHandler(h) { if (h ! == null) { fn(h); }}); };Copy the code

The request interceptor and response interceptor are both implemented using the New InterceptorManager

function Axios(instanceConfig) { this.defaults = instanceConfig; This. Interceptors = {request: new InterceptorManager(), response: new InterceptorManager() }; }Copy the code

By placing the requestInterceptorChain in front of the chain array and the responseInterceptorChain in back, The chain is then traversed (the chain array is paired, one is the interceptor success and failure function, undefined is just a placeholder). Achieve the request interceptor -> API request -> response interceptor execution order.

. Var chain = [dispatchRequest, undefined]; / / the request interceptor arrays requestInterceptorChain on chain in the front of the Array. The prototype. The unshift. Apply (chain, requestInterceptorChain); Chain = chain.concat(responseInterceptorChain); promise = Promise.resolve(config); While (chain.length) {promise = promise.then(chain.shift(), chain.shift()); }...Copy the code

conclusion

The idea of the Axios interceptor is to achieve a certain order of execution by sorting the members of the array and then iterating through the execution.

We can think about 🤔 there is no scene in our work, using this idea can be achieved?