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

4 months ago
/**
* requestresponse拦截器定义
*/
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) => {}, // 请求错误钩子函数集合
};
}