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