仿掘金项目的坑之大数字溢出问题 | 青训营笔记

279 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第8天

大数字溢出问题-- 解决方案

在本次青训营的过程中,遇到的第一个坑 --- 大数溢出问题。

之前不太清楚js 的数据范围,在写项目时,发现后端返回的json 数据中的articleId 的值 比较大,差不多有19位整数,如下图所示:

202208291831817.png 当时出现了一个奇怪的问题,用apipost 和 后端部署的接口文档测试 /content/${id} 的接口都没什么问题,能返回正常的数据,但是前端在接收时就发现后几位数字全部变成了0....

根据百度搜索相关结果:

解决方案1 -- 后端改返回值

由于后端采用雪花算法,生成的文章id (articleId),导致文章id 数据值较大

雪花算法生成的ID是一个64 bitlong型的数字且按时间趋势递增。能够在分布式高并发的环境下,以毫秒级的效率保证id 的唯一性。

前端的Number 的数据范围是 -(2^53 - 1) -- 2^53 - 1

信息来源为mdn的官方文档:

202208291851173.png 但是后端的long 类型的范围是 **- 2 ^ 63 - 2 ^ 63 -1 **,必然会导致一部分值在前端接收json数据时发生溢出的情况。

那么最简单的方式,后端在每一个带有id 的接口返回值,加上 tostring 的处理,这样就可以保证前端接收数据时不会出现精度缺失的问题了。

成功的响应示例:

202208291853510.png

当时我们组第一次遇见这个问题,解决问题是让后端改的接口返回值

解决方案2 -- 前端引入json- bigInt库

json - bigInt 和 axios 解决大数溢出问题:

json-bigint 的npm 官方地址:www.npmjs.com/package/jso…

axios 官方地址:www.npmjs.com/package/axi…

首先我们需要先安装这两个库

npm i json-bigint
npm i axios

json-bigint 的官方文档举例说明:

202208291900943.png

于是我们可以提取出关键的两个api,JSONbig.parse 和 JSONbig.stringify

显然用法与JSON.parse JSON.stringify 两个一样

第一个用于将字符串转换为对象,第二个用于将JSON对象转换为字符串

通过 Axios 请求得到的数据都是 Axios 处理(JSON.parse)之后的,我们应该在 Axios 执行处理之前手动使用 json-bigint 来解析处理。Axios 提供了自定义处理原始后端返回数据的 API:transformResponse

import axios from 'axios';
import JSONBigInt from 'json-bigint'
const myAxios = axios.create({
    baseURL: import.meta.env.VITE_BASE_URL, // 基础路径
    timeout: 5000, // 超时时间
    // transformResponse 允许自定义原始的响应数据(字符串)
    transformResponse: [function (data) {
      return JSONBigInt.parse(data) // 转为bignumber类型的
  }]
});
// 为了便于调试,一般会加上拦截器

// 请求拦截器
myAxios.interceptors.request.use(function(config) {
    // console.log('request', config);
    // Do something before request is sent
    return config;
}, function(error) {
    // Do something with request error
    return Promise.reject(error);
});

// 响应拦截器
myAxios.interceptors.response.use(function(response) {
    // console.log('response', response);
    // Do something with response data
    return response;
}, function(error) {
    // Do something with response error
    return Promise.reject(error);
});

export default myAxios;

如果需要前端将大整数转为string类型的进行展示

import axios from 'axios';
import JSONBigInt from 'json-bigint'

const JSONBigIntStr = JSONBigInt({ storeAsString: true }) // 设置配置项
const myAxios = axios.create({
    transformResponse: [function (data) {
      return JSONBigIntStr.parse(data) // 转为string类型
  }]
});
export default myAxios;

有关JS新内置对象BigInt

通过查询最新的mdn 文档,查到以下信息:

在 JSON 中使用

对任何 BigInt 值使用 JSON.stringify() 都会引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。但是,如果需要,可以实现 toJSON 方法:

BigInt.prototype.toJSON = function() { return this.toString(); }

Copy to Clipboard

JSON.stringify 现在生成如下字符串,而不是抛出异常:

JSON.stringify(BigInt(1));
// '"1"'