2023-08-30 18:05:37 +08:00
|
|
|
import { isExt, isGm } from "./client";
|
2023-08-31 13:38:06 +08:00
|
|
|
import { sendBgMsg } from "./msg";
|
2025-06-27 12:31:32 +08:00
|
|
|
import { getSettingWithDefault } from "./storage";
|
2025-08-31 23:37:29 +08:00
|
|
|
import { MSG_FETCH, DEFAULT_HTTP_TIMEOUT } from "../config";
|
2023-09-20 17:47:23 +08:00
|
|
|
import { isBg } from "./browser";
|
2024-03-19 18:07:18 +08:00
|
|
|
import { kissLog } from "./log";
|
2025-08-31 23:37:29 +08:00
|
|
|
import { getFetchPool } from "./pool";
|
|
|
|
|
import { getHttpCachePolyfill, parseResponse } from "./cache";
|
2024-04-21 13:16:44 +08:00
|
|
|
|
2023-07-20 13:45:41 +08:00
|
|
|
/**
|
2023-08-05 18:15:01 +08:00
|
|
|
* 油猴脚本的请求封装
|
|
|
|
|
* @param {*} input
|
|
|
|
|
* @param {*} init
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2025-07-01 12:38:06 +08:00
|
|
|
export const fetchGM = async (
|
|
|
|
|
input,
|
|
|
|
|
{ method = "GET", headers, body, timeout } = {}
|
|
|
|
|
) =>
|
2023-08-05 18:15:01 +08:00
|
|
|
new Promise((resolve, reject) => {
|
2023-08-16 11:38:53 +08:00
|
|
|
GM.xmlHttpRequest({
|
|
|
|
|
method,
|
|
|
|
|
url: input,
|
|
|
|
|
headers,
|
|
|
|
|
data: body,
|
2023-10-21 11:54:04 +08:00
|
|
|
// withCredentials: true,
|
2025-06-27 12:31:32 +08:00
|
|
|
timeout,
|
2024-04-21 13:16:44 +08:00
|
|
|
onload: ({ response, responseHeaders, status, statusText }) => {
|
2023-10-21 11:54:04 +08:00
|
|
|
const headers = {};
|
2023-09-28 16:18:28 +08:00
|
|
|
responseHeaders.split("\n").forEach((line) => {
|
|
|
|
|
const [name, value] = line.split(":").map((item) => item.trim());
|
|
|
|
|
if (name && value) {
|
2023-10-21 11:54:04 +08:00
|
|
|
headers[name] = value;
|
2023-09-28 16:18:28 +08:00
|
|
|
}
|
|
|
|
|
});
|
2023-10-21 11:54:04 +08:00
|
|
|
resolve({
|
|
|
|
|
body: response,
|
|
|
|
|
headers,
|
|
|
|
|
status,
|
|
|
|
|
statusText,
|
|
|
|
|
});
|
2023-08-16 11:38:53 +08:00
|
|
|
},
|
|
|
|
|
onerror: reject,
|
|
|
|
|
});
|
2023-08-05 18:15:01 +08:00
|
|
|
});
|
2025-06-27 12:31:32 +08:00
|
|
|
|
2023-08-04 17:56:47 +08:00
|
|
|
/**
|
2023-08-10 11:55:40 +08:00
|
|
|
* 发起请求
|
2025-08-31 23:37:29 +08:00
|
|
|
* @param {*} input
|
|
|
|
|
* @param {*} init
|
|
|
|
|
* @param {*} opts
|
2023-08-10 11:55:40 +08:00
|
|
|
* @returns
|
|
|
|
|
*/
|
2025-08-31 23:37:29 +08:00
|
|
|
export const fetchPatcher = async (input, init = {}, opts) => {
|
|
|
|
|
let timeout = opts?.httpTimeout;
|
|
|
|
|
if (!timeout) {
|
2025-07-01 12:38:06 +08:00
|
|
|
try {
|
|
|
|
|
timeout = (await getSettingWithDefault()).httpTimeout;
|
|
|
|
|
} catch (err) {
|
2025-09-24 23:24:00 +08:00
|
|
|
kissLog("getSettingWithDefault", err);
|
2025-07-01 12:38:06 +08:00
|
|
|
}
|
2025-06-27 12:31:32 +08:00
|
|
|
}
|
2025-08-31 23:37:29 +08:00
|
|
|
if (!timeout) {
|
|
|
|
|
timeout = DEFAULT_HTTP_TIMEOUT;
|
|
|
|
|
}
|
2025-06-27 12:31:32 +08:00
|
|
|
|
2023-08-21 23:46:42 +08:00
|
|
|
if (isGm) {
|
2025-07-01 17:55:57 +08:00
|
|
|
// todo: 自定义接口 init 可能包含了 signal
|
|
|
|
|
Object.assign(init, { timeout });
|
|
|
|
|
|
|
|
|
|
const { body, headers, status, statusText } = window.KISS_GM
|
|
|
|
|
? await window.KISS_GM.fetch(input, init)
|
|
|
|
|
: await fetchGM(input, init);
|
|
|
|
|
|
|
|
|
|
return new Response(body, {
|
|
|
|
|
headers: new Headers(headers),
|
|
|
|
|
status,
|
|
|
|
|
statusText,
|
|
|
|
|
});
|
2023-08-10 11:55:40 +08:00
|
|
|
}
|
2023-10-21 11:54:04 +08:00
|
|
|
|
2025-02-17 12:14:10 +08:00
|
|
|
if (AbortSignal?.timeout && !init.signal) {
|
2025-06-27 12:31:32 +08:00
|
|
|
Object.assign(init, { signal: AbortSignal.timeout(timeout) });
|
2024-03-19 14:25:37 +08:00
|
|
|
}
|
|
|
|
|
|
2023-08-10 11:55:40 +08:00
|
|
|
return fetch(input, init);
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-21 13:16:44 +08:00
|
|
|
/**
|
|
|
|
|
* 处理请求
|
2024-04-20 11:52:16 +08:00
|
|
|
* @param {*} param0
|
2023-07-20 13:45:41 +08:00
|
|
|
* @returns
|
|
|
|
|
*/
|
2025-08-31 23:37:29 +08:00
|
|
|
export const fetchHandle = async ({ input, init, opts }) => {
|
|
|
|
|
const res = await fetchPatcher(input, init, opts);
|
2024-04-21 13:16:44 +08:00
|
|
|
return parseResponse(res);
|
|
|
|
|
};
|
2023-07-20 13:45:41 +08:00
|
|
|
|
2024-04-21 13:16:44 +08:00
|
|
|
/**
|
|
|
|
|
* fetch 兼容性封装
|
|
|
|
|
* @param {*} args
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2025-08-31 23:37:29 +08:00
|
|
|
const fetchPolyfill = (args) => {
|
2024-04-21 13:16:44 +08:00
|
|
|
// 插件
|
|
|
|
|
if (isExt && !isBg()) {
|
|
|
|
|
return sendBgMsg(MSG_FETCH, args);
|
2023-07-20 13:45:41 +08:00
|
|
|
}
|
|
|
|
|
|
2024-04-21 13:16:44 +08:00
|
|
|
// 油猴/网页/BackgroundPage
|
|
|
|
|
return fetchHandle(args);
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-20 11:52:16 +08:00
|
|
|
/**
|
2024-04-21 13:16:44 +08:00
|
|
|
* 数据请求
|
2024-04-20 11:52:16 +08:00
|
|
|
* @param {*} input
|
2025-08-31 23:37:29 +08:00
|
|
|
* @param {*} init
|
2024-04-20 11:52:16 +08:00
|
|
|
* @param {*} param1
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2025-08-31 23:37:29 +08:00
|
|
|
export const fetchData = async (
|
|
|
|
|
input,
|
|
|
|
|
init,
|
|
|
|
|
{ useCache, usePool, fetchInterval, fetchLimit, ...opts } = {}
|
|
|
|
|
) => {
|
2023-10-20 17:44:48 +08:00
|
|
|
if (!input?.trim()) {
|
2023-09-06 14:57:02 +08:00
|
|
|
throw new Error("URL is empty");
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
// 使用缓存数据
|
2024-04-21 13:16:44 +08:00
|
|
|
if (useCache) {
|
2025-08-31 23:37:29 +08:00
|
|
|
const resCache = await getHttpCachePolyfill(input, init);
|
|
|
|
|
if (resCache) {
|
|
|
|
|
return resCache;
|
2024-04-21 13:16:44 +08:00
|
|
|
}
|
2023-08-05 18:15:01 +08:00
|
|
|
}
|
|
|
|
|
|
2024-04-21 13:16:44 +08:00
|
|
|
// 通过任务池发送请求
|
|
|
|
|
if (usePool) {
|
2025-08-31 23:37:29 +08:00
|
|
|
const fetchPool = getFetchPool(fetchInterval, fetchLimit);
|
|
|
|
|
return fetchPool.push(fetchPolyfill, { input, init, opts });
|
2024-04-21 13:16:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 直接请求
|
2025-08-31 23:37:29 +08:00
|
|
|
return fetchPolyfill({ input, init, opts });
|
2023-08-11 16:48:09 +08:00
|
|
|
};
|