瀏覽代碼

feat: enhances compatibility with APIs returning large numeric values (#6250)

Netfan 1 月之前
父節點
當前提交
a1091bad46

+ 28 - 0
apps/backend-mock/api/demo/bigint.ts

@@ -0,0 +1,28 @@
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  const data = `
+  {
+    "code": 0,
+    "message": "success",
+    "data": [
+              {
+                "id": 123456789012345678901234567890123456789012345678901234567890,
+                "name": "John Doe",
+                "age": 30,
+                "email": "john-doe@demo.com"
+                },
+                {
+                "id": 987654321098765432109876543210987654321098765432109876543210,
+                "name": "Jane Smith",
+                "age": 25,
+                "email": "jane@demo.com"
+                }
+            ]
+  }
+  `;
+  setHeader(event, 'Content-Type', 'application/json');
+  return data;
+});

+ 4 - 0
playground/package.json

@@ -48,8 +48,12 @@
     "@vueuse/core": "catalog:",
     "@vueuse/core": "catalog:",
     "ant-design-vue": "catalog:",
     "ant-design-vue": "catalog:",
     "dayjs": "catalog:",
     "dayjs": "catalog:",
+    "json-bigint": "catalog:",
     "pinia": "catalog:",
     "pinia": "catalog:",
     "vue": "catalog:",
     "vue": "catalog:",
     "vue-router": "catalog:"
     "vue-router": "catalog:"
+  },
+  "devDependencies": {
+    "@types/json-bigint": "catalog:"
   }
   }
 }
 }

+ 10 - 0
playground/src/api/examples/json-bigint.ts

@@ -0,0 +1,10 @@
+import { requestClient } from '#/api/request';
+
+/**
+ * 发起请求
+ */
+async function getBigIntData() {
+  return requestClient.get('/demo/bigint');
+}
+
+export { getBigIntData };

+ 8 - 1
playground/src/api/request.ts

@@ -1,7 +1,7 @@
 /**
 /**
  * 该文件可自行根据业务逻辑进行调整
  * 该文件可自行根据业务逻辑进行调整
  */
  */
-import type { RequestClientOptions } from '@vben/request';
+import type { AxiosResponseHeaders, RequestClientOptions } from '@vben/request';
 
 
 import { useAppConfig } from '@vben/hooks';
 import { useAppConfig } from '@vben/hooks';
 import { preferences } from '@vben/preferences';
 import { preferences } from '@vben/preferences';
@@ -14,6 +14,7 @@ import {
 import { useAccessStore } from '@vben/stores';
 import { useAccessStore } from '@vben/stores';
 
 
 import { message } from 'ant-design-vue';
 import { message } from 'ant-design-vue';
+import JSONBigInt from 'json-bigint';
 
 
 import { useAuthStore } from '#/store';
 import { useAuthStore } from '#/store';
 
 
@@ -25,6 +26,12 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
   const client = new RequestClient({
   const client = new RequestClient({
     ...options,
     ...options,
     baseURL,
     baseURL,
+    transformResponse: (data: any, header: AxiosResponseHeaders) => {
+      // storeAsString指示将BigInt存储为字符串,设为false则会存储为内置的BigInt类型
+      return header.getContentType()?.toString().includes('application/json')
+        ? JSONBigInt({ storeAsString: true }).parse(data)
+        : data;
+    },
   });
   });
 
 
   /**
   /**

+ 10 - 0
playground/src/router/routes/modules/demos.ts

@@ -255,6 +255,16 @@ const routes: RouteRecordRaw[] = [
               title: $t('demos.features.requestParamsSerializer'),
               title: $t('demos.features.requestParamsSerializer'),
             },
             },
           },
           },
+          {
+            name: 'BigIntDemo',
+            path: '/demos/features/json-bigint',
+            component: () =>
+              import('#/views/demos/features/json-bigint/index.vue'),
+            meta: {
+              icon: 'lucide:grape',
+              title: 'JSON BigInt',
+            },
+          },
         ],
         ],
       },
       },
       // 面包屑导航
       // 面包屑导航

+ 39 - 0
playground/src/views/demos/features/json-bigint/index.vue

@@ -0,0 +1,39 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Alert, Button, Card } from 'ant-design-vue';
+
+import { getBigIntData } from '#/api/examples/json-bigint';
+
+const response = ref('');
+function fetchData() {
+  getBigIntData().then((res) => {
+    response.value = res;
+  });
+}
+</script>
+<template>
+  <Page
+    title="JSON BigInt Support"
+    description="解析后端返回的长整数(long/bigInt)。代码位置:playground/src/api/request.ts中的transformResponse"
+  >
+    <Card>
+      <Alert>
+        <template #message>
+          有些后端接口返回的ID是长整数,但javascript原生的JSON解析是不支持超过2^53-1的长整数的。
+          这种情况可以建议后端返回数据前将长整数转换为字符串类型。如果后端不接受我们的建议😡……
+          <br />
+          下面的按钮点击后会发起请求,接口返回的JSON数据中的id字段是超出整数范围的数字,已自动将其解析为字符串
+        </template>
+      </Alert>
+      <Button class="mt-4" type="primary" @click="fetchData">发起请求</Button>
+      <div>
+        <pre>
+        {{ response }}
+        </pre>
+      </div>
+    </Card>
+  </Page>
+</template>

+ 30 - 0
pnpm-lock.yaml

@@ -84,6 +84,9 @@ catalogs:
     '@types/html-minifier-terser':
     '@types/html-minifier-terser':
       specifier: ^7.0.2
       specifier: ^7.0.2
       version: 7.0.2
       version: 7.0.2
+    '@types/json-bigint':
+      specifier: ^1.0.4
+      version: 1.0.4
     '@types/jsonwebtoken':
     '@types/jsonwebtoken':
       specifier: ^9.0.9
       specifier: ^9.0.9
       version: 9.0.9
       version: 9.0.9
@@ -291,6 +294,9 @@ catalogs:
     is-ci:
     is-ci:
       specifier: ^4.1.0
       specifier: ^4.1.0
       version: 4.1.0
       version: 4.1.0
+    json-bigint:
+      specifier: ^1.0.0
+      version: 1.0.0
     jsonc-eslint-parser:
     jsonc-eslint-parser:
       specifier: ^2.4.0
       specifier: ^2.4.0
       version: 2.4.0
       version: 2.4.0
@@ -1877,6 +1883,9 @@ importers:
       dayjs:
       dayjs:
         specifier: 'catalog:'
         specifier: 'catalog:'
         version: 1.11.13
         version: 1.11.13
+      json-bigint:
+        specifier: 'catalog:'
+        version: 1.0.0
       pinia:
       pinia:
         specifier: ^3.0.2
         specifier: ^3.0.2
         version: 3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))
         version: 3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))
@@ -1886,6 +1895,10 @@ importers:
       vue-router:
       vue-router:
         specifier: 'catalog:'
         specifier: 'catalog:'
         version: 4.5.1(vue@3.5.13(typescript@5.8.3))
         version: 4.5.1(vue@3.5.13(typescript@5.8.3))
+    devDependencies:
+      '@types/json-bigint':
+        specifier: 'catalog:'
+        version: 1.0.4
 
 
   scripts/turbo-run:
   scripts/turbo-run:
     dependencies:
     dependencies:
@@ -4341,6 +4354,9 @@ packages:
   '@types/html-minifier-terser@7.0.2':
   '@types/html-minifier-terser@7.0.2':
     resolution: {integrity: sha512-mm2HqV22l8lFQh4r2oSsOEVea+m0qqxEmwpc9kC1p/XzmjLWrReR9D/GRs8Pex2NX/imyEH9c5IU/7tMBQCHOA==}
     resolution: {integrity: sha512-mm2HqV22l8lFQh4r2oSsOEVea+m0qqxEmwpc9kC1p/XzmjLWrReR9D/GRs8Pex2NX/imyEH9c5IU/7tMBQCHOA==}
 
 
+  '@types/json-bigint@1.0.4':
+    resolution: {integrity: sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag==}
+
   '@types/json-schema@7.0.15':
   '@types/json-schema@7.0.15':
     resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
     resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
 
 
@@ -5253,6 +5269,9 @@ packages:
     resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
     resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
     engines: {node: '>=4'}
     engines: {node: '>=4'}
 
 
+  bignumber.js@9.3.0:
+    resolution: {integrity: sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==}
+
   binary-extensions@2.3.0:
   binary-extensions@2.3.0:
     resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
     resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
     engines: {node: '>=8'}
     engines: {node: '>=8'}
@@ -7643,6 +7662,9 @@ packages:
     engines: {node: '>=6'}
     engines: {node: '>=6'}
     hasBin: true
     hasBin: true
 
 
+  json-bigint@1.0.0:
+    resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
+
   json-buffer@3.0.1:
   json-buffer@3.0.1:
     resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
     resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
 
 
@@ -14045,6 +14067,8 @@ snapshots:
 
 
   '@types/html-minifier-terser@7.0.2': {}
   '@types/html-minifier-terser@7.0.2': {}
 
 
+  '@types/json-bigint@1.0.4': {}
+
   '@types/json-schema@7.0.15': {}
   '@types/json-schema@7.0.15': {}
 
 
   '@types/jsonwebtoken@9.0.9':
   '@types/jsonwebtoken@9.0.9':
@@ -15115,6 +15139,8 @@ snapshots:
     dependencies:
     dependencies:
       is-windows: 1.0.2
       is-windows: 1.0.2
 
 
+  bignumber.js@9.3.0: {}
+
   binary-extensions@2.3.0: {}
   binary-extensions@2.3.0: {}
 
 
   bindings@1.5.0:
   bindings@1.5.0:
@@ -17775,6 +17801,10 @@ snapshots:
 
 
   jsesc@3.1.0: {}
   jsesc@3.1.0: {}
 
 
+  json-bigint@1.0.0:
+    dependencies:
+      bignumber.js: 9.3.0
+
   json-buffer@3.0.1: {}
   json-buffer@3.0.1: {}
 
 
   json-parse-even-better-errors@2.3.1: {}
   json-parse-even-better-errors@2.3.1: {}

+ 2 - 0
pnpm-workspace.yaml

@@ -41,6 +41,7 @@ catalog:
   '@types/archiver': ^6.0.3
   '@types/archiver': ^6.0.3
   '@types/eslint': ^9.6.1
   '@types/eslint': ^9.6.1
   '@types/html-minifier-terser': ^7.0.2
   '@types/html-minifier-terser': ^7.0.2
+  '@types/json-bigint': ^1.0.4
   '@types/jsonwebtoken': ^9.0.9
   '@types/jsonwebtoken': ^9.0.9
   '@types/lodash.clonedeep': ^4.5.9
   '@types/lodash.clonedeep': ^4.5.9
   '@types/lodash.get': ^4.4.9
   '@types/lodash.get': ^4.4.9
@@ -112,6 +113,7 @@ catalog:
   happy-dom: ^17.4.6
   happy-dom: ^17.4.6
   html-minifier-terser: ^7.2.0
   html-minifier-terser: ^7.2.0
   is-ci: ^4.1.0
   is-ci: ^4.1.0
+  json-bigint: ^1.0.0
   jsonc-eslint-parser: ^2.4.0
   jsonc-eslint-parser: ^2.4.0
   jsonwebtoken: ^9.0.2
   jsonwebtoken: ^9.0.2
   lefthook: ^1.11.12
   lefthook: ^1.11.12