feat: use ofetch imitate got

This commit is contained in:
DIYgod
2024-03-23 02:03:55 +08:00
parent 1de5789a90
commit e5a9fd46ee
5 changed files with 181 additions and 76 deletions
+79
View File
@@ -0,0 +1,79 @@
import logger from '@/utils/logger';
import { config } from '@/config';
import got, { CancelableRequest, Response as GotResponse, OptionsInit, Options, Got } from 'got';
type Response<T> = GotResponse<string> & {
data: T;
status: number;
};
type GotRequestFunction = {
(url: string | URL, options?: Options): CancelableRequest<Response<Record<string, any>>>;
<T>(url: string | URL, options?: Options): CancelableRequest<Response<T>>;
(options: Options): CancelableRequest<Response<Record<string, any>>>;
<T>(options: Options): CancelableRequest<Response<T>>;
};
// @ts-expect-error got instance with custom response type
const custom: {
all?: <T>(list: Array<Promise<T>>) => Promise<Array<T>>;
get: GotRequestFunction;
post: GotRequestFunction;
put: GotRequestFunction;
patch: GotRequestFunction;
head: GotRequestFunction;
delete: GotRequestFunction;
} & GotRequestFunction &
Got = got.extend({
retry: {
limit: config.requestRetry,
statusCodes: [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511, 521, 522, 524],
},
hooks: {
beforeRetry: [
(err, count) => {
logger.error(`Request ${err.options.url} fail, retry attempt #${count}: ${err}`);
},
],
beforeRedirect: [
(options, response) => {
logger.http(`Redirecting to ${options.url} for ${response.requestUrl}`);
},
],
afterResponse: [
// @ts-expect-error custom response type
(response: Response<Record<string, any>>) => {
try {
response.data = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
} catch {
// @ts-expect-error for compatibility
response.data = response.body;
}
response.status = response.statusCode;
return response;
},
],
init: [
(
options: OptionsInit & {
data?: string;
}
) => {
// compatible with axios api
if (options && options.data) {
options.body = options.body || options.data;
}
},
],
},
headers: {
'user-agent': config.ua,
},
timeout: {
request: config.requestTimeout,
},
});
custom.all = (list) => Promise.all(list);
export default custom;
export type { Response, Options } from 'got';
+57 -76
View File
@@ -1,79 +1,60 @@
import logger from '@/utils/logger';
import { config } from '@/config';
import got, { CancelableRequest, Response as GotResponse, OptionsInit, Options, Got } from 'got';
import { destr } from 'destr';
import ofetch from '@/utils/ofetch';
type Response<T> = GotResponse<string> & {
data: T;
status: number;
};
type GotRequestFunction = {
(url: string | URL, options?: Options): CancelableRequest<Response<Record<string, any>>>;
<T>(url: string | URL, options?: Options): CancelableRequest<Response<T>>;
(options: Options): CancelableRequest<Response<Record<string, any>>>;
<T>(options: Options): CancelableRequest<Response<T>>;
};
// @ts-expect-error got instance with custom response type
const custom: {
all?: <T>(list: Array<Promise<T>>) => Promise<Array<T>>;
get: GotRequestFunction;
post: GotRequestFunction;
put: GotRequestFunction;
patch: GotRequestFunction;
head: GotRequestFunction;
delete: GotRequestFunction;
} & GotRequestFunction &
Got = got.extend({
retry: {
limit: config.requestRetry,
statusCodes: [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511, 521, 522, 524],
},
hooks: {
beforeRetry: [
(err, count) => {
logger.error(`Request ${err.options.url} fail, retry attempt #${count}: ${err}`);
},
],
beforeRedirect: [
(options, response) => {
logger.http(`Redirecting to ${options.url} for ${response.requestUrl}`);
},
],
afterResponse: [
// @ts-expect-error custom response type
(response: Response<Record<string, any>>) => {
try {
response.data = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
} catch {
// @ts-expect-error for compatibility
response.data = response.body;
}
response.status = response.statusCode;
return response;
},
],
init: [
(
options: OptionsInit & {
data?: string;
}
) => {
// compatible with axios api
if (options && options.data) {
options.body = options.body || options.data;
}
},
],
},
headers: {
'user-agent': config.ua,
},
timeout: {
request: config.requestTimeout,
},
const gotofetch = ofetch.create({
parseResponse: (responseText) => ({
data: destr(responseText),
body: responseText,
}),
});
custom.all = (list) => Promise.all(list);
export default custom;
export type { Response, Options } from 'got';
const getFakeGot = (defaultOptions?: any) => {
const fakeGot = (request, options) => {
if (options?.hooks?.beforeRequest) {
for (const hook of options.hooks.beforeRequest) {
hook(options);
}
}
if (!(typeof request === 'string' || request instanceof Request) && request.url) {
options = {
...request,
...options,
};
request = request.url;
}
options = {
...defaultOptions,
...options,
};
if (options?.json && !options.body) {
options.body = options.json;
}
if (options?.form && !options.body) {
const body = new FormData();
for (const key in options.form) {
body.append(key, options.form[key]);
}
options.body = body;
if (!options.headers) {
options.headers = {};
}
options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
return gotofetch(request, options);
};
fakeGot.get = (request, options) => fakeGot(request, { ...options, method: 'GET' });
fakeGot.post = (request, options) => fakeGot(request, { ...options, method: 'POST' });
fakeGot.put = (request, options) => fakeGot(request, { ...options, method: 'PUT' });
fakeGot.patch = (request, options) => fakeGot(request, { ...options, method: 'PATCH' });
fakeGot.head = (request, options) => fakeGot(request, { ...options, method: 'HEAD' });
fakeGot.delete = (request, options) => fakeGot(request, { ...options, method: 'DELETE' });
fakeGot.extend = (options) => getFakeGot(options);
return fakeGot;
};
export default getFakeGot();
+17
View File
@@ -0,0 +1,17 @@
import { ofetch } from 'ofetch';
import { config } from '@/config';
import logger from '@/utils/logger';
const rofetch = ofetch.create({
retry: config.requestRetry,
retryDelay: 1000,
timeout: config.requestTimeout,
headers: {
'user-agent': config.ua,
},
onRequestError({ request, error }) {
logger.error(`Request ${request.url} fail: ${error}`);
},
});
export default rofetch;
+2
View File
@@ -63,6 +63,7 @@
"crypto-js": "4.2.0",
"currency-symbol-map": "5.1.0",
"dayjs": "1.11.8",
"destr": "2.0.3",
"directory-import": "3.2.1",
"dotenv": "16.4.5",
"entities": "4.5.0",
@@ -89,6 +90,7 @@
"module-alias": "2.2.3",
"notion-to-md": "3.1.1",
"oauth-1.0a": "2.2.6",
"ofetch": "1.3.4",
"otplib": "12.0.1",
"pac-proxy-agent": "7.0.1",
"proxy-chain": "2.4.0",
+26
View File
@@ -53,6 +53,9 @@ dependencies:
dayjs:
specifier: 1.11.8
version: 1.11.8
destr:
specifier: 2.0.3
version: 2.0.3
directory-import:
specifier: 3.2.1
version: 3.2.1
@@ -131,6 +134,9 @@ dependencies:
oauth-1.0a:
specifier: 2.2.6
version: 2.2.6
ofetch:
specifier: 1.3.4
version: 1.3.4
otplib:
specifier: 12.0.1
version: 12.0.1
@@ -4085,6 +4091,10 @@ packages:
engines: {node: '>=6'}
dev: true
/destr@2.0.3:
resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==}
dev: false
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
@@ -6798,6 +6808,10 @@ packages:
- supports-color
dev: true
/node-fetch-native@1.6.4:
resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==}
dev: false
/node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@@ -6920,6 +6934,14 @@ packages:
/object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
/ofetch@1.3.4:
resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==}
dependencies:
destr: 2.0.3
node-fetch-native: 1.6.4
ufo: 1.5.3
dev: false
/on-exit-leak-free@2.1.2:
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
engines: {node: '>=14.0.0'}
@@ -8764,6 +8786,10 @@ packages:
resolution: {integrity: sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==}
dev: true
/ufo@1.5.3:
resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
dev: false
/uglify-js@3.4.10:
resolution: {integrity: sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==}
engines: {node: '>=0.8.0'}