Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Because uniapp network request uni.request return callback function, and there is no request interception to be implemented by itself, but found uniapp uview framework encapsulated request is very good, so it is used separately
Here are the tool functions needed for deep cloning and object deep merging
// deep merge of JS objects
function deepMerge(target = {}, source = {}) {
target = deepClone(target);
if (typeoftarget ! = ='object' || typeofsource ! = ='object') return false;
for (var prop in source) {
if(! source.hasOwnProperty(prop))continue;
if (prop in target) {
if (typeoftarget[prop] ! = ='object') {
target[prop] = source[prop];
} else {
if (typeofsource[prop] ! = ='object') {
target[prop] = source[prop];
} else {
if (target[prop].concat && source[prop].concat) {
target[prop] = target[prop].concat(source[prop]);
} else{ target[prop] = deepMerge(target[prop], source[prop]); }}}}else{ target[prop] = source[prop]; }}return target;
}
// Deep clone
function deepClone (obj) {
// For common "not" values, return the original value directly
if([null.undefined.NaN.false].includes(obj)) return obj;
if(typeofobj ! = ="object" && typeofobj ! = ='function') {
// The primitive type returns directly
return obj;
}
var o = isArray(obj) ? [] : {};
for(let i in obj) {
if(obj.hasOwnProperty(i)){
o[i] = typeof obj[i] === "object"? deepClone(obj[i]) : obj[i]; }}return o;
}
/** * Verify the URL format */
function testUrl(value) {
return /http(s)? :\/\/([\w-]+\.) +[\w-]+(\/[\w-.\/?%&=]*)? /.test(value)
}
Copy the code
It is encapsulated in the form of the Request class, and is used to generate the instance of the Request class. The Request interceptor can execute the incoming callback function before the Request, add token, add signature, etc., and then make the network Request after processing, while the response interceptor formats the data of the response, as detailed in the notes
class Request {
// Set the global default configuration
setConfig(customConfig) {
// Merge objects in depth, otherwise deep attributes of the object will be lost
this.config = deepMerge(this.config, customConfig);
}
// The main request section
request(options = {}) {
// Check request interception
if (this.interceptor.request && typeof this.interceptor.request === 'function') {
let tmpConfig = {};
let interceptorRequest = this.interceptor.request(options);
if (interceptorRequest === false) {
// Return a Promise in a pending state to cancel the original Promise and avoid the then() callback
return new Promise(() = >{});
}
this.options = interceptorRequest;
}
options.dataType = options.dataType || this.config.dataType;
options.responseType = options.responseType || this.config.responseType;
options.url = options.url || ' ';
options.params = options.params || {};
options.header = Object.assign({}, this.config.header, options.header);
options.method = options.method || this.config.method;
return new Promise((resolve, reject) = > {
options.complete = (response) = > {
// Hide loading after the request is returned (if the request is returned quickly, no loading may occur)
uni.hideLoading();
// Clear the timer. If the request comes back, no loading is required
clearTimeout(this.config.timer);
this.config.timer = null;
If originalData is true, return all data (response) to the interceptor, otherwise return only response.data
if(this.config.originalData) {
// Determine whether an interceptor exists
if (this.interceptor.response && typeof this.interceptor.response === 'function') {
let resInterceptors = this.interceptor.response(response);
// If the interceptor does not return false, the interceptor returns the content to the then callback of this.$u.post
if(resInterceptors ! = =false) {
resolve(resInterceptors);
} else {
// If the interceptor returns false, it means that the interceptor definer thinks there is a problem with the return and calls the catch callback directlyreject(response); }}else {
// If raw data is required, the original data is returned, even if there is no interceptorresolve(response); }}else {
if (response.statusCode == 200) {
if (this.interceptor.response && typeof this.interceptor.response === 'function') {
let resInterceptors = this.interceptor.response(response.data);
if(resInterceptors ! = =false) {
resolve(resInterceptors);
} else{ reject(response.data); }}else {
// If originalData is not returned and there is no interceptor, pure data is returned to the then callbackresolve(response.data); }}else {
// When the original data is not returned, the server status code is not 200, and the modal pop-up prompts
// if(response.errMsg) {
// uni.showModal({
// title: response.errMsg
/ /});
// }
reject(response)
}
}
}
// Determine if the URL passed by the user begins with a /, and if not, add a /, using the URL () method of uView's test.js validation library
options.url = testUrl(options.url) ? options.url : (this.config.baseUrl + (options.url.indexOf('/') = =0 ?
options.url : '/' + options.url));
// Whether to display loading
If there are two simultaneous requests, the latter will clear the timer ID of the former
// If the former timer is not cleared, the former times out and loading is displayed
if(this.config.showLoading && !this.config.timer) {
this.config.timer = setTimeout(() = > {
uni.showLoading({
title: this.config.loadingText,
mask: this.config.loadingMask
})
this.config.timer = null;
}, this.config.loadingTime);
}
uni.request(options);
})
// .catch(res => {
/ / / / if return reject (), don't let it into the enclosing $u.p ost (). Then (). The catch () at the back of the catct ()
// // Because many people forget to write catch(), an error is reported that a catch is not caught
// return new Promise(()=>{});
// })
}
constructor() {
this.config = {
baseUrl: ' '.// The requested root domain name
// The default request header
header: {},
method: 'POST'.// Set to JSON and uni.request will parse the data once it is returned
dataType: 'json'.// This parameter needs no processing, because 5+ and Alipay applet do not support, the default is text
responseType: 'text'.showLoading: true.// Whether to display loading in the request
loadingText: 'In the request... '.loadingTime: 800.// If the request is not returned within this time, the loading animation is displayed in ms
timer: null./ / timer
originalData: false.// Whether to return server raw data in interceptor, see documentation
loadingMask: true.// Show whether loading is covered with a transparent layer to prevent touch penetration
}
/ / the interceptor
this.interceptor = {
// Interception before request
request: null.// Interception after request
response: null}}export default new Request
Copy the code
You can also customize the request function after inheritance, such as uploading images, etc., and obtain the configuration information of the instance in real time
/ / get request
this.get = (url, data = {}, header = {}) = > {
return this.request({
method: 'GET',
url,
header,
data
})
}
/ / post request
this.post = (url, data = {}, header = {}) = > {
return this.request({
url,
method: 'POST',
header,
data
})
}
// Put request does not support Alipay small program (HX2.6.15)
this.put = (url, data = {}, header = {}) = > {
return this.request({
url,
method: 'PUT',
header,
data
})
}
// Delete request, alipay and Toutiao are not supported (HX2.6.15)
this.delete = (url, data = {}, header = {}) = > {
return this.request({
url,
method: 'DELETE',
header,
data
})
}
}
Copy the code