You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* request、response拦截器定义
*/
const interceptors = {
request: {
interceptors: [],
use(func) {
return this.interceptors.push(func); // 返回长度, 作为识别id
},
eject(interceptor) {
if (typeof interceptor === "number") {
const rs = this.interceptors.splice(interceptor - 1, 1); //返回一个列表
return rs.length > 0; //length > 0 : 删除成功
} else {
const index = this.interceptors.indexOf(interceptor);
const rs = this.interceptors.splice(index, 1); //返回一个列表
return rs.length > 0; //length > 0 : 删除成功
}
},
intercept(config, url, method, data) {
this.interceptors.forEach((it) => {
config = it(config, url, method, data);
});
return config;
},
},
response: {
interceptors: [],
use(func) {
return this.interceptors.push(func);
},
eject(interceptor) {
if (typeof interceptor === "number") {
const rs = this.interceptors.splice(interceptor - 1, 1); //返回一个列表
return rs.length > 0; //length > 0 : 删除成功
} else {
const index = this.interceptors.indexOf(interceptor);
const rs = this.interceptors.splice(index, 1); //返回一个列表
return rs.length > 0; //length > 0 : 删除成功
}
},
intercept(response, url, method, data) {
this.interceptors.forEach((it) => {
response = it(response, url, method, data);
});
return response;
},
},
};
export default function ({
baseUrl,
timeout = 15000,
header: headers,
codes = [200, 401],
}) {
return {
interceptors,
/**
* 主要功能
* @param url 请求地址
* @param method 请求方式, 默认GET
* @param data 请求参数
* @param header 请求头
*/
request({ url, method = "GET", data, header, enableChunked = false }) {
let aborted = false, //// aborted 请求是否已被取消
requestTask, // requestTask 网络请求 task 对象
abort = () => {
// abort 取消请求方法
aborted = true; // 将请求状态标记为已取消
requestTask && requestTask.abort(); // 执行取消请求方法
},
timer, // timer 检测超时定时器
overtime = false; // overtime 请求是否超时
// header传入
let config = {
header: {
...headers,
...header,
}, // 后面覆盖前面规则
body: data || {},
};
let target = new Promise((resolve, reject) => {
// 请求拦截
let {
header,
body: data,
cancel,
} = this.interceptors.request.intercept(config, url, method, data);
if (aborted || cancel) {
// 如果请求已被取消,停止执行,返回 reject
return (
this.onerror("网络请求失败:主动取消") ||
reject("网络请求失败:主动取消")
);
}
// 请求超时执行方法
timer = setTimeout((_) => {
overtime = true; // 将状态标记为超时,不会被 fail 中的 onerror 重复执行
requestTask && requestTask.abort(); // 执行取消请求方法
reject("网络请求时间超时"); // reject 原因
}, timeout || 15000); // 设定检测超时定时器
requestTask = uni.request({
url: url[0] === "/" ? baseUrl + url : url,
data,
method,
header,
enableChunked,
success: (res) => {
// 网络请求成功
// 清除检测超时定时器
clearTimeout(timer);
if (!codes.includes(res.statusCode)) {
this.onerror(
`网络请求异常:服务器响应异常:状态码:${res.statusCode}`
) ||
reject(
`网络请求异常:服务器响应异常:状态码:${res.statusCode}`
);
} else {
res = this.interceptors.response.intercept(
res,
url,
method,
data
); // 执行响应拦截器
resolve(res.data);
}
},
fail: (res) => {
// 网络请求失败
// 清除检测超时定时器
clearTimeout(timer);
// 如果不是请求超时
if (overtime) {
this.onerror(method, url, data, res || "请求超时") ||
reject(res || "请求超时");
} else {
const errorMsg = aborted
? "网络请求失败:主动取消"
: "网络请求失败URL无效|无网络|DNS解析失败";
this.onerror(method, url, data, errorMsg) || reject(errorMsg);
}
},
});
});
let handler = {
get: (target, prop) => {
// 如果调用 abort 方法,返回 abort 方法
if (prop === "abort") {
return abort;
} else {
if (Reflect.get(target, prop) && Reflect.get(target, prop).bind) {
return Reflect.get(target, prop).bind(target);
} else {
return Reflect.get(target, prop);
}
}
},
};
// 返回经过 Proxy 后的 Promise 对象使其可以监听到是否调用 abort 方法
let proxy = new Proxy(target, handler);
return proxy;
},
file({
url,
method = "downloadFile",
data = {},
header,
onProgressUpdate,
}) {
let aborted = false, //// aborted 请求是否已被取消
requestTask, // requestTask 网络请求 task 对象
abort = () => {
// abort 取消请求方法
aborted = true; // 将请求状态标记为已取消
requestTask ? requestTask.abort() : ""; // 执行取消请求方法
},
timer, // timer 检测超时定时器
overtime = false; // overtime 请求是否超时
// header传入
let config = {
header: {
...headers,
...header,
}, // 后面覆盖前面规则
body: data.formData || {},
};
let target = new Promise((resolve, reject) => {
// 请求拦截
let { header, body, cancel } = this.interceptors.request.intercept(
config,
url,
method,
data
);
if (aborted || cancel) {
// 如果请求已被取消,停止执行,返回 reject
return (
this.onerror(method, url, data, "网络请求失败:主动取消") ||
reject("网络请求失败:主动取消")
);
}
// 请求超时执行方法
timer = setTimeout((_) => {
overtime = true; // 将状态标记为超时,不会被 fail 中的 onerror 重复执行
requestTask.abort(); // 执行取消请求方法
reject("网络请求时间超时"); // reject 原因
}, timeout || 15000); // 设定检测超时定时器
requestTask = uni[method]({
url: url[0] === "/" ? baseUrl + url : url,
name: data.name,
header,
filePath: data.filePath,
formData: body,
success: (res) => {
// 网络请求成功
// 清除检测超时定时器
clearTimeout(timer);
if (!codes.includes(res.statusCode)) {
this.onerror(
method,
url,
data,
`网络请求异常:服务器响应异常:状态码:${res.statusCode}`
) ||
reject(
`网络请求异常:服务器响应异常:状态码:${res.statusCode}`
);
} else {
// 执行响应拦截器
res = this.interceptors.response.intercept(
res,
url,
method,
data
); // 执行响应拦截器
resolve(res);
}
},
fail: (res) => {
// 网络请求失败
// 清除检测超时定时器
clearTimeout(timer);
if (aborted) {
reject("网络请求失败:主动取消");
} else {
reject("网络请求失败URL无效|无网络|DNS解析失败");
}
},
});
requestTask.onProgressUpdate(onProgressUpdate); // 监听下载进度变化
});
let handler = {
get: (target, prop) => {
// 如果调用 abort 方法,返回 abort 方法
if (prop === "abort") {
return abort;
} else {
if (Reflect.get(target, prop) && Reflect.get(target, prop).bind) {
return Reflect.get(target, prop).bind(target);
} else {
return Reflect.get(target, prop);
}
}
},
};
// 返回经过 Proxy 后的 Promise 对象使其可以监听到是否调用 abort 和 onProgressUpdate 方法
let proxy = new Proxy(target, handler);
return proxy;
},
get(url, data, header) {
return this.request({
url,
data,
header: { ...header, ...headers },
});
},
post(url, data, header) {
return this.request({
url,
data,
method: "POST",
header: { ...header, ...headers },
});
},
put(url, data, header) {
return this.request({
url,
data,
method: "PUT",
header: { ...header, ...headers },
});
},
delete(url, data, header) {
return this.request({
method: "DELETE",
url,
data,
header: { ...header, ...headers },
});
},
connect(url, data, header) {
return this.request({
method: "CONNECT",
url,
data,
header: { ...header, ...headers },
});
},
head(url, data, header) {
return this.request({
method: "HEAD",
url,
data,
header: { ...header, ...headers },
});
},
options(url, data, header) {
return this.request({
url,
data,
method: "OPTIONS",
header: { ...header, ...headers },
});
},
reace(url, data, header) {
return this.request({
url,
data,
method: "TRACE",
header: { ...header, ...headers },
});
},
upload(url, onProgressUpdate, data, header) {
return this.file({
url,
method: "uploadFile",
data,
header: { ...header, ...headers },
onProgressUpdate,
});
},
download(url, onProgressUpdate, data, header) {
return this.file({
url,
method: "downloadFile",
data,
header: { ...header, ...headers },
onProgressUpdate,
});
},
onerror: (...args) => {}, // 请求错误钩子函数集合
};
}