Przeglądaj źródła

fix: request download and upload not support `responseReturn` (#5456)

* fix: request download and upload not support `responseReturn`

* docs: update

* fix: type of request client upload result
Netfan 2 miesięcy temu
rodzic
commit
e225159cce

+ 2 - 0
packages/effects/request/src/request-client/modules/downloader.test.ts

@@ -31,6 +31,7 @@ describe('fileDownloader', () => {
     expect(result).toEqual(mockBlob);
     expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {
       responseType: 'blob',
+      responseReturn: 'body',
     });
   });
 
@@ -51,6 +52,7 @@ describe('fileDownloader', () => {
     expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {
       ...customConfig,
       responseType: 'blob',
+      responseReturn: 'body',
     });
   });
 

+ 22 - 12
packages/effects/request/src/request-client/modules/downloader.ts

@@ -1,7 +1,14 @@
-import type { AxiosRequestConfig } from 'axios';
-
 import type { RequestClient } from '../request-client';
-import type { RequestResponse } from '../types';
+import type { RequestClientConfig } from '../types';
+
+type DownloadRequestConfig = {
+  /**
+   * 定义期望获得的数据类型。
+   * raw: 原始的AxiosResponse,包括headers、status等。
+   * body: 只返回响应数据的BODY部分(Blob)
+   */
+  responseReturn?: 'body' | 'raw';
+} & Omit<RequestClientConfig, 'responseReturn'>;
 
 class FileDownloader {
   private client: RequestClient;
@@ -9,20 +16,23 @@ class FileDownloader {
   constructor(client: RequestClient) {
     this.client = client;
   }
-
-  public async download(
+  /**
+   * 下载文件
+   * @param url 文件的完整链接
+   * @param config 配置信息,可选。
+   * @returns 如果config.responseReturn为'body',则返回Blob(默认),否则返回RequestResponse<Blob>
+   */
+  public async download<T = Blob>(
     url: string,
-    config?: AxiosRequestConfig,
-  ): Promise<RequestResponse<Blob>> {
-    const finalConfig: AxiosRequestConfig = {
+    config?: DownloadRequestConfig,
+  ): Promise<T> {
+    const finalConfig: DownloadRequestConfig = {
+      responseReturn: 'body',
       ...config,
       responseType: 'blob',
     };
 
-    const response = await this.client.get<RequestResponse<Blob>>(
-      url,
-      finalConfig,
-    );
+    const response = await this.client.get<T>(url, finalConfig);
 
     return response;
   }

+ 5 - 6
packages/effects/request/src/request-client/modules/uploader.ts

@@ -1,6 +1,5 @@
-import type { AxiosRequestConfig, AxiosResponse } from 'axios';
-
 import type { RequestClient } from '../request-client';
+import type { RequestClientConfig } from '../types';
 
 class FileUploader {
   private client: RequestClient;
@@ -9,18 +8,18 @@ class FileUploader {
     this.client = client;
   }
 
-  public async upload(
+  public async upload<T = any>(
     url: string,
     data: Record<string, any> & { file: Blob | File },
-    config?: AxiosRequestConfig,
-  ): Promise<AxiosResponse> {
+    config?: RequestClientConfig,
+  ): Promise<T> {
     const formData = new FormData();
 
     Object.entries(data).forEach(([key, value]) => {
       formData.append(key, value);
     });
 
-    const finalConfig: AxiosRequestConfig = {
+    const finalConfig: RequestClientConfig = {
       ...config,
       headers: {
         'Content-Type': 'multipart/form-data',

+ 7 - 7
packages/effects/request/src/request-client/preset-interceptors.ts

@@ -25,15 +25,15 @@ export const defaultResponseInterceptor = ({
       if (config.responseReturn === 'raw') {
         return response;
       }
-      const code = responseData[codeField];
-      if (
-        status >= 200 && status < 400 && isFunction(successCode)
-          ? successCode(code)
-          : code === successCode
-      ) {
+
+      if (status >= 200 && status < 400) {
         if (config.responseReturn === 'body') {
           return responseData;
-        } else {
+        } else if (
+          isFunction(successCode)
+            ? successCode(responseData[codeField])
+            : responseData[codeField] === successCode
+        ) {
           return isFunction(dataField)
             ? dataField(responseData)
             : responseData[dataField];

+ 3 - 3
packages/effects/request/src/request-client/types.ts

@@ -7,9 +7,9 @@ import type {
 
 type ExtendOptions = {
   /** 响应数据的返回方式。
-   * raw: 原始的AxiosResponse,包括headers、status等。
-   * body: 返回响应数据的BODY部分。
-   * data: 解构响应的BODY数据,只返回其中的data节点数据。
+   * raw: 原始的AxiosResponse,包括headers、status等,不做是否成功请求的检查
+   * body: 返回响应数据的BODY部分(只会根据status检查请求是否成功,忽略对code的判断,这种情况下应由调用方检查请求是否成功)
+   * data: 解构响应的BODY数据,只返回其中的data节点数据(会检查status和code是否为成功状态)
    */
   responseReturn?: 'body' | 'data' | 'raw';
 };

+ 28 - 0
playground/src/api/examples/download.ts

@@ -0,0 +1,28 @@
+import type { RequestResponse } from '@vben/request';
+
+import { requestClient } from '../request';
+
+/**
+ * 下载文件,获取Blob
+ * @returns Blob
+ */
+async function downloadFile1() {
+  return requestClient.download<Blob>(
+    'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+  );
+}
+
+/**
+ * 下载文件,获取完整的Response
+ * @returns RequestResponse<Blob>
+ */
+async function downloadFile2() {
+  return requestClient.download<RequestResponse<Blob>>(
+    'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+    {
+      responseReturn: 'raw',
+    },
+  );
+}
+
+export { downloadFile1, downloadFile2 };

+ 26 - 0
playground/src/views/demos/features/file-download/index.vue

@@ -1,4 +1,6 @@
 <script setup lang="ts">
+import { ref } from 'vue';
+
 import { Page } from '@vben/common-ui';
 import {
   downloadFileFromBase64,
@@ -9,7 +11,23 @@ import {
 
 import { Button, Card } from 'ant-design-vue';
 
+import { downloadFile1, downloadFile2 } from '#/api/examples/download';
+
 import imageBase64 from './base64';
+
+const downloadResult = ref('');
+
+function getBlob() {
+  downloadFile1().then((res) => {
+    downloadResult.value = `获取Blob成功,长度:${res.size}`;
+  });
+}
+
+function getResponse() {
+  downloadFile2().then((res) => {
+    downloadResult.value = `获取Response成功,headers:${JSON.stringify(res.headers)},长度:${res.data.size}`;
+  });
+}
 </script>
 
 <template>
@@ -70,5 +88,13 @@ import imageBase64 from './base64';
         Download TxT
       </Button>
     </Card>
+
+    <Card class="my-5" title="Request download">
+      <Button type="primary" @click="getBlob"> 获取Blob </Button>
+      <Button type="primary" class="ml-4" @click="getResponse">
+        获取Response
+      </Button>
+      <div class="mt-4">{{ downloadResult }}</div>
+    </Card>
   </Page>
 </template>