background

Recently, I am cooperating with friends to develop an enterprise micro application, which may need to use two interfaces

  • Internal interface: Requires token, authorization and other request header fields.
  • External interface: Directly call

Thinking back

Mainly is the use of ES6 class keyword to define a request class, in the class to define a static method (static), static method instances can not be called, the class can be directly called; The class also defines various requests (POST, postJson, GET, PUT, putJson, delete), etc., and sets its configuration separately for each request. Finally, axios.create([config]).then((result)=>{}), etc.

File directory level


base.js
Request.js
LSRequest.js
Copy the code

implementation

base.js

// Make it easy to change
export OPEN_URL = "xxx.xxx.xxx";/ / external base
export INNER_URL = "xxx.xxx.xxx";/ / internal base
Copy the code

Request.js(External interface calls)

import axios from "axios";
// The Axios plug-in retries the failed request
import axiosRetry from "axios-retry";
// QS is a library for parsing and serializing query strings with some added security.
import qs from "qs";
// The prompt window applies vant's Toast component
import {Toast} from 'vant';
axiosRetry(axios, {
  retries: 3.retryCondition: () = > true.retryDelay: () = > 1000
});
let toastCount = 0;
// Request interceptor
axios.interceptors.request.use(
  config= > {
     if(! config._asyn) { Toast.loading({message: 'Loading... '.forbidClick: true.duration: 0}); toastCount++; }return config;
  },
  err= > {
    console.log(err);
    return Promise.reject(err); });// Response interceptor
axios.interceptors.response.use(
  response= > {
    if(! response.config._asyn) { toastCount--;if (toastCount <= 0) { Toast.clear(); }}return response;
  },
  err= > {
    toastCount--;
    if (toastCount <= 0) {
      Toast.clear();
    }
    return Promise.reject(err); });// Define a Request class with the class keyword
export default class Request {

 Constructor, and the this keyword represents the instance object.
  constructor(url) {
    this.requestConfig = {url: url, headers: {}};
  }
  
  // A class is the prototype of an instance. All methods defined in a class are inherited by the instance.If you have a method, plus`static`Keyword, indicating that the method is not inherited by the instance, but is called directly from the class, which is called a "static method."static create(url) {
    return new Request(url);
  }

  asyn() {
    this.requestConfig._asyn = true;
    return this;
  }

  header(key, value) {
    this.requestConfig.headers[key] = value;
    return this;
  }

  post(param) {
    this.requestConfig.method = 'post';
    this.requestConfig.data = qs.stringify(param, {
       skipNulls: true.//skipNulls can ignore nulls resolution:
       encodeValuesOnly: true.// You can disable URI encoding for keys by setting encodeValuesOnly to true:
       indices: false.//indices if false do not display index:
    });
    this.header("Content-Type"."application/x-www-form-urlencoded");
    return this.execute();
  }

  postJson(param) {
    this.requestConfig.method = 'post';
    this.requestConfig.data = param;
    this.header("Content-Type"."application/json");
    return this.execute();
  }

  get(param) {
    this.requestConfig.method = 'get';
    this.requestConfig.params = param;
    this.requestConfig.paramsSerializer = params= >
      qs.stringify(params, {
        skipNulls: true.encodeValuesOnly: true.indices: false});this.header("Content-Type"."application/x-www-form-urlencoded");
    return this.execute();
  }

  /** * put call application/x-www-form-urlencoded *@param Param parameter *@returns {Promise<unknown>}* /
  put(param) {
    this.requestConfig.method = 'put';
    this.requestConfig.data = qs.stringify(param, {
      skipNulls: true.encodeValuesOnly: true.indices: false
    });
    this.header("Content-Type"."application/x-www-form-urlencoded");
    return this.execute();
  }

  /** * put calls application/json *@param Param parameter *@returns {Promise<unknown>}* /
  putJson(param) {
    this.requestConfig.method = 'put';
    this.requestConfig.data = param;
    this.header("Content-Type"."application/json");
    return this.execute();
  }

  /** * coded application/x-www-form-urlencoded *@param Param parameter *@returns {Promise<unknown>}* /
  delete(param) {
    this.requestConfig.method = 'delete';
    this.requestConfig.params = param;
    this.requestConfig.paramsSerializer = params= >
      qs.stringify(params, {
        skipNulls: true.encodeValuesOnly: true.indices: false});this.header("Content-Type"."application/x-www-form-urlencoded");
    return this.execute();
  }


  execute() {
    // Create a new axiOS instance with the custom configuration
    return axios.request(this.requestConfig).then(response= > {
      return Promise.resolve(response.data); }); }}Copy the code

Lsrequest.js (internal call)

import Request from "./Request";
import {Toast} from 'vant';
import { INNER_URL } from "./base";// Request path defined in base.js
// Whether the tag is being refreshed
let isRefresh = false;
// Retry queue, each item will be a function to be executed
let requests = [];

function flushToken(action) {
  // Queue resolve, save it as a function, and execute it directly after token refresh
  let p = new Promise(resolve= > {
    requests.push(() = > {
      resolve(action());
    });
  });
  if(! isRefresh) { isRefresh =true;
    LsRequest.create("userauth/token/refresh").post({
      authorization: sessionStorage.getItem("authorization"),
      refresh_token: sessionStorage.getItem("refreshToken")
    }).then(token= > {
      sessionStorage.setItem("authorization", token.principal);
      sessionStorage.setItem("token", token.token);
      sessionStorage.setItem("refreshToken", token.refreshToken);
      requests.forEach(callback= > callback());
      requests = [];
    });
  }
  return p;
}

const baseUrl = INNER_URL;
export default class LsRequest extends Request {
  constructor(url) {
    if(! url.startsWith("/")) {
      url = "/" + url;
    }
    // The super key can only appear in the specified form in the constructor function of a subclass;The keyword is used to access functions on the parent object,super(baseUrl + url);
  }

  static create(url) {
    return new LsRequest(url);
  }

  execute() {
    // Set some headers
    this.header("authorization", sessionStorage.getItem("authorization"));
    this.header("token", sessionStorage.getItem("token"));
    // Superclass methods can be called from 'super' objects
    return super.execute().then(response= > {
      let data = response.data;
      let code = response.code;
      let message = response.message;
      switch (code) {
        case 200:
          return Promise.resolve(data);
        //4012 Indicates that the token expired and refreshes the token
        case 4012:
          return flushToken(this.execute);
        case 406:
          Toast.fail(message);
          break;
        case 4011:
          // Clear the cached data and redirect to the home page
          sessionStorage.clear();
          router.replace({
             path: "/"
           });
          break;
        case 400:
          Toast.fail("Parameter error:" + message);
          break;
        case 401:
          Toast.fail("Permission error");
          break;
        case 404:
          Toast.fail("04 NOT FOUND");
          break;
        case 500:
          Toast.fail("The network has wandered off.");
          break;
        default:
          break;
      }
      return Promise.reject({code: code, message: message}); }); }}Copy the code

Mount the exported methods above globally in mian.js

Vue.prototype.nativeRequest = Request.create;
Vue.prototype.request = LsRequest.create;
Copy the code

Call it where needed:

// Internal call
  getNoticeList() {
        this.request("case-field/message/userMessage")
          .get({})
          .then(result= >{... }); },// External call
 getAudioList(){
 this.nativeRequest( this.ML_URL+'/leSoft/audio/' + id)
            .get({ })
            .then((r) = >{... }); },Copy the code

Ps: I wrote it secretly at work. I panicked