Packaging ideas

Index. ts We need to create an axios folder in the SRC root directory and create an index.ts file that encapsulates the AXIos configuration (instantiated request configuration, request interceptor, corresponding interceptor) and corresponding methods (login jump, message prompt, error handling, etc.).

Base.ts this file is mainly used in the case of project extension, different modules need to call different interfaces (the base address of the request baseURL) and the preparation in the early stage is convenient for the later maintenance

Request. ts encapsulates axios-based configuration methods such as GET, POST, PUT, and delete.

Api. ts introduces this module in main.ts, including all interface data information written to this file.

index.ts

The package is as follows. Considering the single responsibility, the index block encapsulates only AXIos

// index.ts
import axios, { AxiosRequestConfig, Method } from "axios";
import router from "@/router";
import store from "@/store";
import { message } from 'ant-design-vue'
import { storage } from ".. /storage/storage";
import { dataList } from "@/components/aspin/data";

/** * redirects to the login page */ Carries a route to the current page in order to return to the current page after the login page is complete
const toLogin = () = > {
  router.replace({
    name: 'LoginPage'}); }/** * Request failed error unified processing *@param {Number} Status Indicates the status code of the failed request */
const errorHandle = (status: number, other: string) = > {
  // Determine the status code
  switch (status) {

    case 302: message.error('Interface redirected! ');
      break;
    case 400:
      message.error("Error in request sent, server did not create or modify data ==>" + status)
      break;
    // 401: Not logged in
    // If you do not log in, the login page is displayed and the path of the current page is displayed
    // Return to the current page after successful login. This step must be performed on the login page.
    case 401: / / redirection
      message.error("Token: Login invalid ==>" + status + ":" + store.state.Roles)
      storage.remove(store.state.Roles)
      storage.get(store.state.Roles)
      router.replace({
        path: '/Login'});break;
    // 403 Token expired
    // Clear the token and jump to the login page
    case 403:
      message.error("Login expired, user is authorized, but access is prohibited ==>" + status)
      // store.commit('token', null);
      setTimeout(() = > {
        router.replace({
          path: '/Login'}); },1000);
      break;
    case 404:
      message.error("Network request does not exist ==>" + status)
      break;
    case 406:
      message.error("Requested format not available ==>" + status)
      break;
    case 408: message.error("Request timed out!")
      break;
    case 410:
      message.error("Requested resource permanently deleted and no longer available ==>" + status)
      break;
    case 422:
      message.error("A validation error occurred while creating an object ==>" + status)
      break;
    case 500:
      message.error("Server error, please check server ==>" + status)
      break;
    case 502:
      message.error("Gateway error ==>" + status)
      break;
    case 503:
      message.error("Service unavailable, server temporarily overloaded or maintenance ==>" + status)
      break;
    case 504:
      message.error("Gateway timeout ==>" + status)
      break;
    default:
      message.error("Other errors error ==>" + status)
  }
}

// Define the interfaceinterface PendingType { url? : string; method? : Method; params: any; data: any; cancel: any; }// Cancel duplicate requests
const pending: Array<PendingType> = [];
const CancelToken = axios.CancelToken;

// Remove duplicate requests
const removePending = (config: AxiosRequestConfig) = > {
  for (const key in pending) {
    const item: number = +key;
    const list: PendingType = pending[key];
    // Execute the function body when the current request exists in the array
    if (list.url === config.url && list.method === config.method && JSON.stringify(list.params) === JSON.stringify(config.params) && JSON.stringify(list.data) === JSON.stringify(config.data)) {
      // Perform the cancel operation
      list.cancel('Operation too frequent, please try again later');
      // Remove the record from the array
      pending.splice(item, 1); }}};/* Instantiate the request configuration */
const instance = axios.create({
  headers: {
    // the PHP post request header must have this or it will not receive the value
    "Content-Type": "application/json; charset=UTF-8"."Access-Control-Allow-Origin-Type": The '*'
  },
  // Request duration
  timeout: 1000 * 30.// The requested base addressTODO:This will change the API for different modules later
  baseURL: process.env.VUE_APP_API_URL,
  / /? "Test"
  // : "official ",
  // Indicates whether credentials are required for cross-domain requests
  withCredentials: false,})/** * Request interceptor * Each request is preceded by a token */ in the request header if it exists
instance.interceptors.request.use(
  config= > {

    removePending(config);
    config.cancelToken = new CancelToken((c) = > {
      pending.push({ url: config.url, method: config.method, params: config.params, data: config.data, cancel: c });
    });
    // During login process control, users can be judged based on whether tokens exist locally
    // But even if the token exists, it is possible that the token is expired, so the token is carried in the request header each time
    // The background determines the login status of the user according to the token carried and returns the corresponding status code to us
    // Then we can do some uniform operations based on the status code in the response interceptor.
    // const token = store.state.token;
    // localStorage.setItem('token', token);

    if (storage.get(store.state.Roles)) {
      store.state.Roles
      config.headers.Authorization = storage.get(store.state.Roles);
    }
    return config;
  },
  error= > {
    message.error(error.data.error.message);
    return Promise.reject(error.data.error.message); })// Response interceptor
instance.interceptors.response.use(function (config) {

  dataList.show = true
  removePending(config.config);
  // The request succeeded
  if (config.status === 200 || config.status === 204) {
    setTimeout(() = > {
      dataList.show = false
    }, 400)
    return Promise.resolve(config);
  } else {
    return Promise.reject(config);
  }
  // The request failed
}, function (error) {

  const { response } = error;
  if (response) {
    errorHandle(response.status, response.data.message);

    // Retry the timeout request
    const config = error.config;
    // The number of global requests, the gap between requests
    const [RETRY_COUNT, RETRY_DELAY] = [3.1000];

    if (config && RETRY_COUNT) {
      // Sets the variable used to track retry counts
      config.__retryCount = config.__retryCount || 0;
      // Check whether the total number of retries has been used up
      if (config.__retryCount >= RETRY_COUNT) {
        return Promise.reject(response || { message: error.message });
      }
      // Increase the retry count
      config.__retryCount++;
      // Create new Promises to handle exponential fallbacks
      const backoff = new Promise<void> ((resolve) = > {
        setTimeout(() = > {
          resolve();
        }, RETRY_DELAY || 1);
      });
      // Instance retry the request Promise
      return backoff.then(() = > {
        return instance(config);
      });
    }

    return Promise.reject(response);
  } else {
    // Handle network outages
    // If the request times out or the network is disconnected, update the network status of state
    // The network state controls the display and hiding of a global disconnection alert component in app.vue
    // Add some operations in the case of disconnection
    store.commit('networkState'.false); }})// Just consider a single responsibility, which encapsulates only AXIos
export default instance
Copy the code

base.ts

The baseUrl of each module is differentiated to facilitate later maintenance and management

// base.ts
export class Base {
  /* Public module */
  static env = process.env.NODE_ENV === "development"
    ? "http://localhost:8087"
    : "Https://produceCommon.com (production line address)"
}
Copy the code

You can also set it directly in index.ts so that you don’t need base.ts

const instance = axios.create({
  // The requested base addressTODO:This will change the API for different modules later
  baseURL: process.env.VUE_APP_API_URL,
})
Copy the code

The root directory needs to be configured

.env.development

     NODE_ENV = 'development'
 	 # VUE_APP_API_URL = 'https://localhost:5001/'
    VUE_APP_API_URL = 'http://localhost:8087/'
Copy the code

.env.production

NODE_ENV = 'production' VUE_APP_API_URL = 'http://129.xxxxx/'Copy the code

request.ts

Wrap axios’ GET and POST methods, and the rest of the interface calls can also be written to this file for easy management.

// request.ts
import axios from "./index";
import qs from "qs";

export class Request {
  /** * get method *@param {string} The url path *@param {object} Params parameters * /
  static get = (url: string, params? : any) = > {
    return new Promise((resolve, reject) = > {
      axios.get(url, { params: params }).then(res= > {
        resolve(res);
      }).catch(err= >{ reject(err); })})}static post = (url: string, params? : any) = > {
    return new Promise((resolve, reject) = > {
      axios.post(url, qs.stringify(params)).then(res= > {
        resolve(res);
      }).catch(err= >{ reject(err); }}})})Copy the code

api.ts

Vue page to use the API interface

// The purpose of using install is for ts in main.ts
// Can't be called directly through vue.prototype. $Api
// The global method will talk about mounting using plug-ins.
// api.ts
import { Base } from "./base";
import { Request } from "./request";

class api {
  /* API interface module */
  public static article = {
     // Set directly in index.ts without the Base module
    genre: () = > Request.get('/api/SnArticle/GetCountAsync'),
     // Encapsulate the call based on the Base module
    genres: () = > Request.get(`${Base.env}/api/SnArticle/GetCountAsync`),}}export {
  api
}
Copy the code

index.vue

import { api } from '.. /.. /utils/api/api'
import { onMounted } from 'vue'
onMounted(async() = > {await QueryAll()
  api.article.genre().then((res: any) = > {
    console.log('genre' + res.data)
  })
  api.article.genres().then((res: any) = > {
    console.log('genres' + res.data)
  })
})
Copy the code

reference

Blog.csdn.net/qq_40031303…