add query adapter

This commit is contained in:
熊潇 2025-06-07 17:00:30 +08:00
parent 452f821d06
commit 14dec5f5c5
3 changed files with 18 additions and 5 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@kevisual/query", "name": "@kevisual/query",
"version": "0.0.25", "version": "0.0.26",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/index.js", "module": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View File

@ -1,12 +1,15 @@
export const methods = ['GET', 'POST'] as const; export const methods = ['GET', 'POST'] as const;
export type Method = (typeof methods)[number]; export type Method = (typeof methods)[number];
type SimpleObject = Record<string, any>;
export type AdapterOpts = { export type AdapterOpts = {
url?: string; url?: string;
headers?: Record<string, string>; headers?: Record<string, string>;
body?: Record<string, any>; body?: Record<string, any> | FormData; // body 可以是对象、字符串或 FormData
timeout?: number; timeout?: number;
method?: Method; method?: Method;
isBlob?: boolean; // 是否返回 Blob 对象 isBlob?: boolean; // 是否返回 Blob 对象
isPostFile?: boolean; // 是否为文件上传
}; };
export const isTextForContentType = (contentType: string | null) => { export const isTextForContentType = (contentType: string | null) => {
if (!contentType) return false; if (!contentType) return false;
@ -23,6 +26,7 @@ export const adapter = async (opts: AdapterOpts, overloadOpts?: RequestInit) =>
const controller = new AbortController(); const controller = new AbortController();
const signal = controller.signal; const signal = controller.signal;
const isBlob = opts.isBlob || false; // 是否返回 Blob 对象 const isBlob = opts.isBlob || false; // 是否返回 Blob 对象
const isPostFile = opts.isPostFile || false; // 是否为文件上传
const timeout = opts.timeout || 60000 * 3; // 默认超时时间为 60s * 3 const timeout = opts.timeout || 60000 * 3; // 默认超时时间为 60s * 3
const timer = setTimeout(() => { const timer = setTimeout(() => {
controller.abort(); controller.abort();
@ -38,7 +42,15 @@ export const adapter = async (opts: AdapterOpts, overloadOpts?: RequestInit) =>
} }
const isGet = method === 'GET'; const isGet = method === 'GET';
if (isGet) { if (isGet) {
url.search = new URLSearchParams(opts.body).toString(); url.search = new URLSearchParams(opts.body as SimpleObject).toString();
}
let body: string | FormData | undefined = undefined;
if (isGet) {
body = undefined;
} else if (isPostFile) {
body = opts.body as FormData; // 如果是文件上传,直接使用 FormData
} else {
body = JSON.stringify(opts.body); // 否则将对象转换为 JSON 字符串
} }
return fetch(url, { return fetch(url, {
method: method.toUpperCase(), method: method.toUpperCase(),
@ -48,7 +60,7 @@ export const adapter = async (opts: AdapterOpts, overloadOpts?: RequestInit) =>
}, },
signal, signal,
...overloadOpts, ...overloadOpts,
body: isGet ? undefined : JSON.stringify(opts.body), body: body,
}) })
.then(async (response) => { .then(async (response) => {
// 获取 Content-Type 头部信息 // 获取 Content-Type 头部信息

View File

@ -16,10 +16,11 @@ export type Fn = (opts: {
export type QueryOpts = { export type QueryOpts = {
url?: string; url?: string;
headers?: Record<string, string>; headers?: Record<string, string>;
body?: Record<string, any>; body?: Record<string, any> | FormData; // body 可以是对象、字符串或 FormData
timeout?: number; timeout?: number;
method?: Method; method?: Method;
isBlob?: boolean; // 是否返回 Blob 对象 isBlob?: boolean; // 是否返回 Blob 对象
isPostFile?: boolean; // 是否为文件上传
adapter?: typeof adapter; adapter?: typeof adapter;
[key: string]: any; [key: string]: any;