@nsnanocat/util 1.8.1 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/polyfill/fetch.mjs +86 -70
package/package.json
CHANGED
package/polyfill/fetch.mjs
CHANGED
|
@@ -8,32 +8,42 @@ import { Lodash as _ } from "./Lodash.mjs";
|
|
|
8
8
|
* @link https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API
|
|
9
9
|
* @export
|
|
10
10
|
* @async
|
|
11
|
-
* @param {object|string}
|
|
12
|
-
* @param {object} [
|
|
11
|
+
* @param {object|string} resource
|
|
12
|
+
* @param {object} [options]
|
|
13
13
|
* @returns {Promise<object>}
|
|
14
14
|
*/
|
|
15
|
-
export async function fetch(
|
|
15
|
+
export async function fetch(resource, options = {}) {
|
|
16
16
|
// 初始化参数
|
|
17
|
-
switch (
|
|
18
|
-
case
|
|
19
|
-
|
|
17
|
+
switch (typeof resource) {
|
|
18
|
+
case "object":
|
|
19
|
+
resource = { ...options, ...resource };
|
|
20
20
|
break;
|
|
21
|
-
case
|
|
22
|
-
|
|
21
|
+
case "string":
|
|
22
|
+
resource = { ...options, url: resource };
|
|
23
23
|
break;
|
|
24
|
+
case "undefined":
|
|
25
|
+
default:
|
|
26
|
+
throw new TypeError(`${Function.name}: 参数类型错误, resource 必须为对象或字符串`);
|
|
24
27
|
}
|
|
25
28
|
// 自动判断请求方法
|
|
26
|
-
if (!
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
+
if (!resource.method) {
|
|
30
|
+
resource.method = "GET";
|
|
31
|
+
if (resource.body ?? resource.bodyBytes) resource.method = "POST";
|
|
29
32
|
}
|
|
30
33
|
// 移除请求头中的部分参数, 让其自动生成
|
|
31
|
-
delete
|
|
32
|
-
delete
|
|
33
|
-
delete
|
|
34
|
-
delete
|
|
34
|
+
delete resource.headers?.Host;
|
|
35
|
+
delete resource.headers?.[":authority"];
|
|
36
|
+
delete resource.headers?.["Content-Length"];
|
|
37
|
+
delete resource.headers?.["content-length"];
|
|
35
38
|
// 定义请求方法(小写)
|
|
36
|
-
const method =
|
|
39
|
+
const method = resource.method.toLocaleLowerCase();
|
|
40
|
+
// 转换请求超时时间参数
|
|
41
|
+
if (!resource.timeout) resource.timeout = 5;
|
|
42
|
+
if (resource.timeout) {
|
|
43
|
+
resource.timeout = Number.parseInt(resource.timeout, 10);
|
|
44
|
+
// 转换为秒,大于500视为毫秒,小于等于500视为秒
|
|
45
|
+
if (resource.timeout > 500) resource.timeout = Math.round(resource.timeout / 1000);
|
|
46
|
+
}
|
|
37
47
|
// 判断平台
|
|
38
48
|
switch ($app) {
|
|
39
49
|
case "Loon":
|
|
@@ -43,41 +53,40 @@ export async function fetch(request, option) {
|
|
|
43
53
|
case "Shadowrocket":
|
|
44
54
|
default:
|
|
45
55
|
// 转换请求参数
|
|
46
|
-
if (
|
|
47
|
-
request.timeout = Number.parseInt(request.timeout, 10);
|
|
56
|
+
if (resource.timeout) {
|
|
48
57
|
switch ($app) {
|
|
49
58
|
case "Loon":
|
|
59
|
+
resource.timeout = resource.timeout * 1000;
|
|
60
|
+
break;
|
|
50
61
|
case "Shadowrocket":
|
|
51
62
|
case "Stash":
|
|
52
63
|
case "Egern":
|
|
53
|
-
default:
|
|
54
|
-
request.timeout = request.timeout / 1000;
|
|
55
|
-
break;
|
|
56
64
|
case "Surge":
|
|
65
|
+
default:
|
|
57
66
|
break;
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
|
-
if (
|
|
69
|
+
if (resource.policy) {
|
|
61
70
|
switch ($app) {
|
|
62
71
|
case "Loon":
|
|
63
|
-
|
|
72
|
+
resource.node = resource.policy;
|
|
64
73
|
break;
|
|
65
74
|
case "Stash":
|
|
66
|
-
_.set(
|
|
75
|
+
_.set(resource, "headers.X-Stash-Selected-Proxy", encodeURI(resource.policy));
|
|
67
76
|
break;
|
|
68
77
|
case "Shadowrocket":
|
|
69
|
-
_.set(
|
|
78
|
+
_.set(resource, "headers.X-Surge-Proxy", resource.policy);
|
|
70
79
|
break;
|
|
71
80
|
}
|
|
72
81
|
}
|
|
73
|
-
if (typeof
|
|
82
|
+
if (typeof resource.redirection === "boolean") resource["auto-redirect"] = resource.redirection;
|
|
74
83
|
// 转换请求体
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
if (resource.bodyBytes && !resource.body) {
|
|
85
|
+
resource.body = resource.bodyBytes;
|
|
86
|
+
resource.bodyBytes = undefined;
|
|
78
87
|
}
|
|
79
88
|
// 判断是否请求二进制响应体
|
|
80
|
-
switch ((
|
|
89
|
+
switch ((resource.headers?.Accept || resource.headers?.accept)?.split(";")?.[0]) {
|
|
81
90
|
case "application/protobuf":
|
|
82
91
|
case "application/x-protobuf":
|
|
83
92
|
case "application/vnd.google.protobuf":
|
|
@@ -85,19 +94,19 @@ export async function fetch(request, option) {
|
|
|
85
94
|
case "application/grpc":
|
|
86
95
|
case "application/grpc+proto":
|
|
87
96
|
case "application/octet-stream":
|
|
88
|
-
|
|
97
|
+
resource["binary-mode"] = true;
|
|
89
98
|
break;
|
|
90
99
|
}
|
|
91
100
|
// 发送请求
|
|
92
101
|
return await new Promise((resolve, reject) => {
|
|
93
|
-
$httpClient[method](
|
|
102
|
+
$httpClient[method](resource, (error, response, body) => {
|
|
94
103
|
if (error) reject(error);
|
|
95
104
|
else {
|
|
96
105
|
response.ok = /^2\d\d$/.test(response.status);
|
|
97
106
|
response.statusCode = response.status;
|
|
98
107
|
if (body) {
|
|
99
108
|
response.body = body;
|
|
100
|
-
if (
|
|
109
|
+
if (resource["binary-mode"] == true) response.bodyBytes = body;
|
|
101
110
|
}
|
|
102
111
|
resolve(response);
|
|
103
112
|
}
|
|
@@ -105,51 +114,58 @@ export async function fetch(request, option) {
|
|
|
105
114
|
});
|
|
106
115
|
case "Quantumult X":
|
|
107
116
|
// 转换请求参数
|
|
108
|
-
if (
|
|
109
|
-
if (typeof
|
|
117
|
+
if (resource.policy) _.set(resource, "opts.policy", resource.policy);
|
|
118
|
+
if (typeof resource["auto-redirect"] === "boolean") _.set(resource, "opts.redirection", resource["auto-redirect"]);
|
|
110
119
|
// 转换请求体
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} else if (ArrayBuffer.isView(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
} else if (
|
|
120
|
+
if (resource.body instanceof ArrayBuffer) {
|
|
121
|
+
resource.bodyBytes = resource.body;
|
|
122
|
+
resource.body = undefined;
|
|
123
|
+
} else if (ArrayBuffer.isView(resource.body)) {
|
|
124
|
+
resource.bodyBytes = resource.body.buffer.slice(resource.body.byteOffset, resource.body.byteLength + resource.body.byteOffset);
|
|
125
|
+
resource.body = undefined;
|
|
126
|
+
} else if (resource.body) resource.bodyBytes = undefined;
|
|
118
127
|
// 发送请求
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
response
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
128
|
+
return Promise.race([
|
|
129
|
+
await $task.fetch(resource).then(
|
|
130
|
+
response => {
|
|
131
|
+
response.ok = /^2\d\d$/.test(response.statusCode);
|
|
132
|
+
response.status = response.statusCode;
|
|
133
|
+
switch ((response.headers?.["Content-Type"] ?? response.headers?.["content-type"])?.split(";")?.[0]) {
|
|
134
|
+
case "application/protobuf":
|
|
135
|
+
case "application/x-protobuf":
|
|
136
|
+
case "application/vnd.google.protobuf":
|
|
137
|
+
case "application/vnd.apple.flatbuffer":
|
|
138
|
+
case "application/grpc":
|
|
139
|
+
case "application/grpc+proto":
|
|
140
|
+
case "application/octet-stream":
|
|
141
|
+
response.body = response.bodyBytes;
|
|
142
|
+
break;
|
|
143
|
+
case undefined:
|
|
144
|
+
default:
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
response.bodyBytes = undefined;
|
|
148
|
+
return response;
|
|
149
|
+
},
|
|
150
|
+
reason => Promise.reject(reason.error),
|
|
151
|
+
),
|
|
152
|
+
new Promise((resolve, reject) => {
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
reject(new Error(`${Function.name}: 请求超时, 请检查网络后重试`));
|
|
155
|
+
}, resource.timeout);
|
|
156
|
+
}),
|
|
157
|
+
]);
|
|
142
158
|
case "Node.js": {
|
|
143
159
|
const iconv = require("iconv-lite");
|
|
144
160
|
const got = globalThis.got ? globalThis.got : require("got");
|
|
145
161
|
const cktough = globalThis.cktough ? globalThis.cktough : require("tough-cookie");
|
|
146
162
|
const ckjar = globalThis.ckjar ? globalThis.ckjar : new cktough.CookieJar();
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
if (undefined ===
|
|
163
|
+
if (resource) {
|
|
164
|
+
resource.headers = resource.headers ? resource.headers : {};
|
|
165
|
+
if (undefined === resource.headers.Cookie && undefined === resource.cookieJar) resource.cookieJar = ckjar;
|
|
150
166
|
}
|
|
151
|
-
const { url, ...
|
|
152
|
-
return await got[method](url,
|
|
167
|
+
const { url, ...options } = resource;
|
|
168
|
+
return await got[method](url, options)
|
|
153
169
|
.on("redirect", (response, nextOpts) => {
|
|
154
170
|
try {
|
|
155
171
|
if (response.headers["set-cookie"]) {
|