preface

The controller code has just been pruned out of the project and there may be some errors or bloatcode

An identifier is required to intrude into the request header to mark the current request (optional)

Controller Introduction

  • ⚠️ Can automatically close the non-routed page request after enabling the jump route (code is too intrusive, temporarily not open, can be designed by oneself)
  • ✅ Enables the global loading box
  • ✅ Enables disabling repeated requests
  • ✅ Enables or disables repeated requests
  • ✅ By default, requests with different parameters are not identified as the same request
  • 😞 When a large amount of data is used, only defined parameters are used as the basis for repeated requests

The body of the

dependency

  • axios
  • qs
  • Loading (elementui is self-substitutable)

1. Create controller files

Create a js file in the folder that wraps AXIos. Let’s name it axioshandler.js

Importing dependencies

import axios from "axios"
import qs from "qs"
import { Loading } from "element-ui"
Copy the code

Declare the variables required by the controller

export const MyKey = "my-cancel-close:" // Close the message header to distinguish error messages within a catch
let httpSequences = 0 // Record the request sequence
const pending = new Map(a)// Store request data

// customParams requests custom parameters and description
const CUSTOM_PARAMS = {
  closeOtherPage: false.// {Boolean} Turn off non-routed page requests automatically,TODO:There are limitations, not open
  bodyLoading: false./ / {Boolean | | String} open global load box
  repeat: false.// {Boolean} Duplicate requests are not allowed. Requests with different parameters will not be closed
  closeRepeat: false.// {Boolean} Enable Disables repeated requests. Requests with different parameters will not be closed
  repeatParams: false.// {Boolean} If this parameter is enabled, requests with different parameters are identified as the same request. If this parameter is enabled, repeat or closeRepeat must be enabled
  keys: [] // {Array
      
       } This parameter is used when there is a large amount of data
      
}
Copy the code

2. Control methods

✅ Check whether the same request exists

/** * @param {String} requestUrl; */ export const findPending = (requestUrl) => {const findAll = [] for (const pendingObj of pending.values()) {if (pendingObj.requestUrl === requestUrl) { findAll.push(pendingObj) } } return findAll }Copy the code

✅ Closes a single request

/ * * * @ title close request * @ param {Object | | key} pendingObj request configuration or request sequences * / const delPending = (pendingObj) = > {if (typeof pendingObj == "string" || typeof pendingObj == "number") { const obj = pending.get(pendingObj) obj.cancel(`${MyKey}del`)  pending.delete(pendingObj) } else { pendingObj.cancel(`${MyKey}del`) pending.delete(pendingObj.httpSequences) } }Copy the code

✅ closes requests for the same address

/** * @title * @param {String} requestUrl; */ export const delSamePending = (requestUrl) => {findPending(requestUrl). ForEach (pendingObj => { pendingObj.cancel(`${MyKey}delSame`) pending.delete(pendingObj.httpSequences) }) }Copy the code

✅ Close all requests (support receiving fuzzy address matching off)

*/ export const deleteAllRequest = (match = undefined) => {if (match) { for (const pendingObj of pending.values()) { if (pendingObj.requestUrl.toLowerCase().includes(match.toLowerCase())) { pendingObj.cancel() pending.delete(pendingObj.httpSequences) } } } else { for (const pendingObj of pending.values()) { pendingObj.cancel() }  pending.clear() } }Copy the code

✅ serialize request parameters

/** * @title Serialized request parameters * @param {Object} config Request Object * @param {Array} keys Custom request parameter field * @return {String} request link + request parameter */ export const parseUrl = (config, keys = []) => { const objToStr = (obj = {}) => { if (typeof obj === "string") { obj = JSON.parse(obj) } const newobj = {} keys.forEach(key => { newobj[key] = obj[key] }) return qs.stringify(newobj) } let params if (Array.isArray(keys) && Keys.length) {if (config.method === "get" && config.params) {params = objToStr(config.params) } else if (config.method === "post" && config.data) { params = objToStr(config.data) } } if (! Params) {if (config.method === "post") {params = objToStr(config.data)} else {// All non-POST requests use params = objToStr(config.params) } } let configUrl = config.url configUrl += configUrl.includes("?" )? `&${params}` : `? ${params}` return configUrl }Copy the code

Three, the pre-processing before initiating the request

/** * @title * @param {Object} config config configuration */ export const interceptorsRequest = (config = {}) => { const pendingObj = {} const customParams = { ... CUSTOM_PARAMS, ... config? . CustomParams | | {}} pendingObj. CustomParams = customParams / / clean up configuration parameters the if (config. CustomParams) {config. CustomParams = Delete config.customParams} undefined // Insert a key into the request header for sequence identification

Return new Promise((resolve, reject) => {// Convert the request link to the format we want const configUrl = parseUrl(config, CustomParams. Keys) let requestUrl if (customParams repeatParams) {/ / different parameters are considered to be the same request, RequestUrl = configurl.split ("?") )[0] + "&" + config.method + "&myRepeatParams" } else { requestUrl = configUrl + "&" + config.method if (customParams.repeat) { requestUrl = requestUrl + "&myRepeat" } else if (customParams.closeRepeat) { requestUrl = requestUrl + "&myCloseRepeat" } }

If (customParams.repeat) {if (findPending(requestUrl).length) {return reject(new) Error(' ${MyKey}no-repeat '))}} else if (customParams.closerepeat) { CancelToken = new axios. cancelToken (cancel => {pendingobj.requestURL = RequestUrl Pendingobj.cancel = cancel}) // If (CustomParams.bodyLoading && Loading) {pendingobj.bodyLoading  = Loading.service({ lock: true, body: true, customClass: "my-loading-body", text: CustomParams. BodyLoading | | "data load..." , spinner: "el-icon-loading", background: "rgba(0, 0, 0, 2)"})} config.headers.MyPending = httpSequences pending. HttpSequences pending. pendingObj) httpSequences = httpSequences + 1 resolve()Copy the code

Copy the code

})}

Iv. Handling of the request after completion

@param {Object} config config configuration of axios */ export const interceptorsResponse = (config = {}) =>  { const pendingObj = pending.get(config.headers? .mypending) if (pendingObj) {// If (pendingobj.myloadingBody) {pendingobj.myloadingBody? .close() } delPending(config.headers? .MyPending) } }Copy the code

5. Formal access project

The preparation work is complete, now we plug into the project code, and use the method is very simple

Open the JS file that wraps AXIOS, such as requist.js in the sample project

// Import processing methods
import { interceptorsRequest, interceptorsResponse, MyKey } from "./axiosHandler"

// Request interceptor
service.interceptors.request.use(async(config) => {
  // HACK:Intercept registered
  await interceptorsRequest(config)
  / /... other code
  return config
}, error= > {
  return Promise.reject(error)
})
// Response interceptor
service.interceptors.response.use(res= > {
  // HACK:Response interception delete
  interceptorsResponse(res.config)
},
error= > {
  let { message } = error;
  if (message.includes("etwork")) {
    message = "System port connection is abnormal";
  } else if (message.includes("timeout")) {
    message = "System interface request timed out";
  } else if (message.includes("failed")) {
    message = "System port is abnormal";
  }
  // HACK:Whether to close the throw for repeated requests
  if(! message.startsWith(MyKey)) { Message({message: message,
      type: "error".duration: 5 * 1000})}return Promise.reject(error)
})
Copy the code

Six, use examples

Get, Post and other request methods, use the same method, only with customParams

🐛 cannot be re-initiated until the request is completed

return request({
  url: "/login".method: "post",
  data,
  customParams: {
    repeat: true}})Copy the code

🐛 Make a new request close the historical request (it will not be closed if the parameters are inconsistent)

return request({
  url: "/login".method: "post",
  data,
  customParams: {
    closeRepeat: true}})Copy the code

🐛 If the parameters are inconsistent each time, a new request is sent to close the historical request

return request({
  url: "/login".method: "post",
  data,
  customParams: {
    closeRepeat: true.repeatParams: true}})Copy the code

🐛 Used when there is a large amount of data. Initiate new requests and close historical requests

return request({
  url: "/login".method: "post",
  data,
  customParams: {
    closeRepeat: true.keys: ["uuid"]}})Copy the code

Source 📑

/ * * *@title    Axios repeatedly requests control *@author   Azil
 * @version  0.0.1
 * @time     The 2021-11-20 * /
import axios from "axios";
import qs from "qs";
import { Loading } from "element-ui";

// The controller turns off the request information key to distinguish error messages within the catch
export const MyKey = "my-cancel-close:";

let httpSequences = 0; // Record the request sequence
const pending = new Map(a);// Store request data

// customParams requests custom parameters and description
const CUSTOM_PARAMS = {
  closeOtherPage: false.// {Boolean} Automatically closes non-routed page requests after redirect is enabled,TODO:There are limitations, not open
  bodyLoading: false./ / {Boolean | | String} open global load box
  repeat: false.// {Boolean} Duplicate requests are not allowed. Requests with different parameters will not be closed
  closeRepeat: false.// {Boolean} Enable Disables repeated requests. Requests with different parameters will not be closed
  repeatParams: false.// {Boolean} If this parameter is enabled, requests with different parameters are identified as the same request. If this parameter is enabled, repeat or closeRepeat must be enabled
  keys: [].// {Array
      
       } When a large amount of data is used, only parameters from the definition are used as criteria for repeated requests
      
};

/ * * *@title	 Query whether the same request * exists@param	 {String}  RequestUrl specifies the requestUrl with the parameter *@return {Array} The path with the same request parameters */ is displayed
export const findPending = (requestUrl) = > {
  const findAll = [];
  for (const pendingObj of pending.values()) {
    if(pendingObj.requestUrl === requestUrl) { findAll.push(pendingObj); }}return findAll;
};

/ * * *@title	Close the request@param	{Object || key}  PendingObj requests configuration or request sequence */
const delPending = (pendingObj) = > {
  if (typeof pendingObj == "string" || typeof pendingObj == "number") {
    const obj = pending.get(pendingObj);
    obj.cancel(`${MyKey}del`);
    pending.delete(pendingObj);
  } else {
    pendingObj.cancel(`${MyKey}del`); pending.delete(pendingObj.httpSequences); }};/ * * *@title	Close requests * for the same address@param	{String}  RequestUrl Specifies the link to the request with the parameter */
export const delSamePending = (requestUrl) = > {
  findPending(requestUrl).forEach((pendingObj) = > {
    pendingObj.cancel(`${MyKey}delSame`);
    pending.delete(pendingObj.httpSequences);
  });
};

/ * * *@title	Clear all requests *@param	{String}  Match Fuzzy match deleted */
export const deleteAllRequest = (match = undefined) = > {
  if (match) {
    for (const pendingObj of pending.values()) {
      if(pendingObj.requestUrl.toLowerCase().includes(match.toLowerCase())) { pendingObj.cancel(); pending.delete(pendingObj.httpSequences); }}}else {
    for (const pendingObj ofpending.values()) { pendingObj.cancel(); } pending.clear(); }};/ * * *@title	 Serialize request parameters *@param	 {Object}  Config Request object *@param	 {Array}  Keys Custom request parameter field *@return {String} Request link + request parameter */
export const parseUrl = (config, keys = []) = > {
  const objToStr = (obj = {}) = > {
    if (typeof obj === "string") {
      obj = JSON.parse(obj);
    }
    const newobj = {};
    keys.forEach((key) = > {
      newobj[key] = obj[key];
    });
    return qs.stringify(newobj);
  };
  let params;
  if (config.method === "post" || config.method === "put") {
    params = objToStr(config.data);
  } else {
    params = objToStr(config.params);
  }
  let configUrl = config.url;
  configUrl += configUrl.includes("?")?` &${params}` : `?${params}`;
  return configUrl;
};

/ * * *@title	Processing before the request is initiated *@param	{Object} Config Axios config */
export const interceptorsRequest = (config = {}) = > {
  const pendingObj = {};
  constcustomParams = { ... CUSTOM_PARAMS, ... (config? .customParams || {}), }; pendingObj.customParams = customParams;// Clear the configuration parameters
  if (config.customParams) {
    config.customParams = undefined;
    delete config.customParams;
  }

  return new Promise((resolve, reject) = > {
    // Convert the request link to the format we want to process
    const configUrl = parseUrl(config, customParams.keys);
    let requestUrl;
    if (customParams.repeatParams) {
      // Different parameters are considered the same request, but repeat and closeRepeat do not affect each other
      requestUrl = configUrl.split("?") [0] + "&" + config.method + "&myRepeatParams";
    } else {
      requestUrl = configUrl + "&" + config.method;
      if (customParams.repeat) {
        requestUrl = requestUrl + "&myRepeat";
      } else if (customParams.closeRepeat) {
        requestUrl = requestUrl + "&myCloseRepeat"; }}if (customParams.repeat) {
      // Repeat requests are not allowed
      if (findPending(requestUrl).length) {
        return reject(new Error(`${MyKey}no-repeat`)); }}else if (customParams.closeRepeat) {
      // Allow repeated requests to be made, but turn off historical repeated requests and keep only the latest one
      delSamePending(requestUrl);
    }

    config.cancelToken = new axios.CancelToken((cancel) = > {
      pendingObj.requestUrl = requestUrl;
      pendingObj.cancel = cancel;
    });

    // Whether to open the full-screen mask
    if (customParams.bodyLoading && Loading) {
      pendingObj.bodyLoading = Loading.service({
        lock: true.body: true.customClass: "my-loading-body".text: customParams.bodyLoading || "Data loading...".spinner: "el-icon-loading".background: "Rgba (0, 0, 0, 0.5)"}); }// TODO:A key needs to be inserted into the request header for sequence identification
    config.headers.MyPending = httpSequences;

    pendingObj.httpSequences = httpSequences;
    pending.set(httpSequences, pendingObj);
    httpSequences = httpSequences + 1;

    resolve();
  });
};

/ * * *@title	Post-request processing *@param	{Object} Config Axios config */
export const interceptorsResponse = (config = {}) = > {
  constpendingObj = pending.get(config.headers? .MyPending);if (pendingObj) {
    // Disable loading if there is loading
    if(pendingObj.myLoadingBody) { pendingObj.myLoadingBody? .close(); } delPending(config.headers? .MyPending); }};/ * * *@title	Request exception handling */
export const errorHandler = (error) = > {
  console.error(/ Request exception handling /, error);
  for (const pendingObj of pending.values()) {
    // Disable loading if there is loading
    if(pendingObj.myLoadingBody) { pendingObj.myLoadingBody? .close(); }}};Copy the code