“This is the third day of my participation in the November Gwen Challenge. See details of the event: The last Gwen Challenge 2021”.


preface

To begin with, this article will share the ideas and methods of encapsulating HTTP requests that I often use in my work. Since the most commonly used framework in my work is Vue, naturally, this article is based on AXIos

Why encapsulate AXIos

One student might ask, “Why bother wrapping the axios one more time when it’s already great and has everything you need?”

To those who do, I can only say, “Good question. After reading the article, don’t ask again.”

Consider the following questions:

  1. What would you do if you had to set the request header uniformly
  2. What would you do if you wanted to intercept the return value and process the data for a particular interface
  3. What would you do if you had to set up loading animations

It is not difficult to see that the above problems have one thing in common, that is, unified treatment, which is why the need for encapsulation

How to encapsulate

Project directory structure

First we create a service folder in the project directory for the request class. Then we create an HTTP folder in the project folder for the constructor, interceptor, request exit, and aiP1 folder for the specific request. It can also be divided by page structure or component structure, depending on the actual project.)

Detailed interpretation of the

The interceptor

The interceptors. Js file is used to store interceptors. What does the interceptor do

In interceptors, you can do unified handling for request methods, request parameters, interface callback parameters, request exceptions, response exceptions, and so on

Going back to the three questions at the beginning of this article, questions 2 and 3 can be handled inside the interceptor

// service/http/interceptors.js
// HTTP request interceptor
const request = config= > {
    Config is the axiOS request configuration item
    if (config.method === 'get') {
        // do something
    }
    if (config.method === 'post') {
        // do something
    }
    return config;
};

const requestError = err= > {
    const { config, code, message } = err;
    // Here you can do some abnormal monitoring such as error interface, error information collection for online service troubleshooting
    // do something
	
    // Since AXIos returns a PROMISE entity, in error interception, null data is returned to ensure that the interface responds without exception
    return Promise.reject({ code, data: {}}); };// HTTP response interceptor
// Response interceptors are used to cache interfaces in conjunction with caching policies
const response = res= > {
    const { config, data } = res;
    // do something
    return res.data;
};

const responseError = err= > {
    const { config, code, message } = err;
    // Here you can do some abnormal monitoring such as error interface, error information collection for online service troubleshooting
    // do something
	
    // It is also possible to call the cache data on the wrong interface in conjunction with the business cache policy to ensure the normal service
    // do something
	
    // Whether you need to call the cache data to return different entities for different interfaces
    // return data (data from cache)
    return Promise.reject({ code, data: {}}); };export default {
    request,
    requestError,
    response,
    responseError
};
Copy the code

The common use of interceptor production has been mentioned in the code block and above, and more uses can be used to expand the combined business (definitely can play very ridiculous).

The constructor

Constructors, as the name implies, are classes that construct request instances

In the constructor, we can set the interface domain name needed for our business and pass the interceptor instance into the AXIOS instance method

It is worth noting that while we can also do business with the request method in the constructor, in order to maintain the principle of one thing doing one thing, we should just let it construct axios instances separately in the constructor

// service/http/fetch.js
import axios from 'axios';
import intercepors from './interceptors';

// Create different AXIos entities
let fetch1 = createFetchByHost('//host1.cn'.true);
let fetch2 = createFetchByHost('//host2.cn'.false);

// The AXIos entity constructor can be modified according to business requirements
/** * Create fetch *@param {string} url* /
function createFetchByHost(url, withCredentials = false) {
    let http = axios.create({
        baseURL: process.env.NODE_ENV === 'production' ? url : ' '.timeout: 5000.withCredentials: withCredentials,
        headers: { post: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'}}});// Configure the common part of the request header
    http.interceptors.request.use(intercepors.request, intercepors.requestError);
    http.interceptors.response.use(intercepors.response, intercepors.responseError);
    return http;
}

export default { fetch1, fetch2 };
export { fetch1, fetch2 };
Copy the code
Request the export

There’s nothing to be said for the request exit, which simply exposes the axios instance constructed by the constructor and pastes the sample code directly. Right

// service/http/index.js
import { fetch1, fetch2 } from './fetch';

class Api {
    constructor() {
        this.fetch1 = fetch1;
        this.fetch2 = fetch2; }}export default Api;
export { Api };
Copy the code
Service interface encapsulation

We’ve covered interceptors, constructors, request exits, and basically we have a semi-finished product coming up. Now we can encapsulate the specific business interface based on the semi-finished product and we’re done

In the constructor, we construct different axios instances for different domains, and here we will apply these instances to construct specific interface classes. In this way, we can unify processing for a particular interface

Question 3 at the beginning of the article can be dealt with here. In addition, we can also combine interceptor, the specified domain name to do interface cache

// service/api1/index.js
import Api from '.. /http';

class Api1 extends Api {
    async apiA({ params = ' ' }) {
        return this.fetch1.post('/api/path', { params }).catch(() = > ({ result: 'error'.data: {}})); }}export default new Api1();
Copy the code
The service class export

This is also the final step in the encapsulation. After we complete the steps above, expose the Service class for business use

// service/index.js
import { fetch } from './http';
import api1 from './api1';

const install = VUE= > {
    VUE.prototype.$http = fetch;
    VUE.prototype.$httpApi1 = api1;
};

export default { api1, install };

export { api1 as api1Service, install };
Copy the code

When we expose the Service class, we assign the AXIos instance and the business interface instance to the VUE stereotype attribute. This is adjusted according to the business. My personal preference is to do this because it is more convenient…

How to apply

How to apply this thing, so I don’t have to spend too much ink, just post an example

Call / * * * * * * * * * * /
// In the component that references the vue instance
// this.$httpApi1.apiA()

// In pure JS methods
// import { api1Service } from '@/service';
// api1Service.apiA()
Copy the code