From 66905f13a9d0669db0162e145c96d732989d9905 Mon Sep 17 00:00:00 2001 From: xion Date: Mon, 2 Jun 2025 11:36:59 +0800 Subject: [PATCH] =?UTF-8?q?"chore:=20=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E5=8F=8A=E9=80=82=E9=85=8DBlob=E5=93=8D=E5=BA=94"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 8 +++--- src/adapter.ts | 10 ++++++-- src/query.ts | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 9d6965d..4004da1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/query", - "version": "0.0.20", + "version": "0.0.22", "main": "dist/index.js", "module": "dist/index.js", "types": "dist/index.d.ts", @@ -25,12 +25,12 @@ "devDependencies": { "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-typescript": "^12.1.2", - "rollup": "^4.40.2", + "rollup": "^4.41.1", "rollup-plugin-dts": "^6.2.1", "ts-node": "^10.9.2", "tslib": "^2.8.1", "typescript": "^5.8.3", - "zustand": "^5.0.4" + "zustand": "^5.0.5" }, "packageManager": "yarn@1.22.22", "publishConfig": { @@ -59,6 +59,6 @@ } }, "dependencies": { - "openai": "^4.98.0" + "openai": "^5.0.1" } } \ No newline at end of file diff --git a/src/adapter.ts b/src/adapter.ts index 37f3696..f6a3892 100644 --- a/src/adapter.ts +++ b/src/adapter.ts @@ -1,11 +1,12 @@ export const methods = ['GET', 'POST'] as const; export type Method = (typeof methods)[number]; export type AdapterOpts = { - url: string; + url?: string; headers?: Record; body?: Record; timeout?: number; method?: Method; + isBlob?: boolean; // 是否返回 Blob 对象 }; /** @@ -17,6 +18,7 @@ export type AdapterOpts = { export const adapter = async (opts: AdapterOpts, overloadOpts?: RequestInit) => { const controller = new AbortController(); const signal = controller.signal; + const isBlob = opts.isBlob || false; // 是否返回 Blob 对象 const timeout = opts.timeout || 60000 * 3; // 默认超时时间为 60s * 3 const timer = setTimeout(() => { controller.abort(); @@ -47,8 +49,12 @@ export const adapter = async (opts: AdapterOpts, overloadOpts?: RequestInit) => .then((response) => { // 获取 Content-Type 头部信息 const contentType = response.headers.get('Content-Type'); + if (isBlob) { + return response.blob(); // 直接返回 Blob 对象 + } + const isJson = contentType && contentType.includes('application/json'); // 判断返回的数据类型 - if (contentType && contentType.includes('application/json')) { + if (isJson) { return response.json(); // 解析为 JSON } else { return response.text(); // 解析为文本 diff --git a/src/query.ts b/src/query.ts index e418ff4..cac6650 100644 --- a/src/query.ts +++ b/src/query.ts @@ -15,10 +15,13 @@ export type Fn = (opts: { export type QueryOpts = { url?: string; - adapter?: typeof adapter; headers?: Record; + body?: Record; timeout?: number; method?: Method; + isBlob?: boolean; // 是否返回 Blob 对象 + + adapter?: typeof adapter; [key: string]: any; }; export type Data = { @@ -55,7 +58,7 @@ export type DataOpts = Partial & { * showError 是 如果 success 为 false 且 noMsg 为 false, 则调用 showError * @param res 响应 */ -export const setBaseResponse = (res: Result) => { +export const setBaseResponse = (res: Partial) => { res.success = res.code === 200; /** * 显示错误 @@ -66,6 +69,7 @@ export const setBaseResponse = (res: Result) => { fn?.(); } }; + return res as Result; }; export const wrapperError = ({ code, message }: { code?: number; message?: string }) => { const result = { @@ -227,6 +231,68 @@ export class Query { after(fn: DataOpts['afterResponse']) { this.afterResponse = fn; } + async fetchText(urlOrOptions?: string | QueryOpts, options?: QueryOpts): Promise> { + let _options = { ...options }; + if (typeof urlOrOptions === 'string' && !_options.url) { + _options.url = urlOrOptions; + } + if (typeof urlOrOptions === 'object') { + _options = { ...urlOrOptions, ..._options }; + } + const res = await adapter({ + method: 'GET', + ..._options, + headers: { + ...this.headers, + ...(_options?.headers || {}), + }, + }); + if (!res.ok) { + return wrapperError({ + code: res.status, + message: `fetch error: ${res.statusText}`, + }); + } + const contentType = res.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await res.json(); + const result = { code: res.status, data, success: res.ok }; + return setBaseResponse(result); + } + if (contentType && contentType.includes('text/html')) { + const text = await res.text(); + const result: Partial = { + code: res.status, + data: text, + success: res.ok, + }; + return setBaseResponse(result); + } + if (contentType && contentType.includes('text/plain')) { + let text = await res.text(); + // 处理特殊情况,比如返回的是纯文本 + if (text.startsWith('{')) { + try { + text = JSON.parse(text); + } catch (e) { + // 如果解析失败,保持原样 + } + } + const result: Partial = { + code: res.status, + data: text, + success: res.ok, + }; + return setBaseResponse(result); + } + const blob = await res.blob(); + const result: Partial = { + code: res.status, + data: blob, + success: res.ok, + }; + return setBaseResponse(result); + } } export { adapter };