这是我参与「第四届青训营 」笔记创作活动的的第8天
大数字溢出问题-- 解决方案
在本次青训营的过程中,遇到的第一个坑 --- 大数溢出问题。
之前不太清楚js 的数据范围,在写项目时,发现后端返回的json 数据中的articleId 的值 比较大,差不多有19位整数,如下图所示:
当时出现了一个奇怪的问题,用apipost 和 后端部署的接口文档测试 /content/${id} 的接口都没什么问题,能返回正常的数据,但是前端在接收时就发现后几位数字全部变成了0....
根据百度搜索相关结果:
解决方案1 -- 后端改返回值
由于后端采用雪花算法,生成的文章id (articleId),导致文章id 数据值较大
雪花算法生成的ID是一个64 bit的long
型的数字且按时间趋势递增。能够在分布式高并发的环境下,以毫秒级的效率保证id 的唯一性。
前端的Number 的数据范围是 -(2^53 - 1) -- 2^53 - 1
信息来源为mdn的官方文档:
但是后端的
long
类型的范围是 **- 2 ^ 63 - 2 ^ 63 -1 **,必然会导致一部分值在前端接收json数据时发生溢出的情况。
那么最简单的方式,后端在每一个带有id 的接口返回值,加上 tostring 的处理,这样就可以保证前端接收数据时不会出现精度缺失的问题了。
成功的响应示例:
当时我们组第一次遇见这个问题,解决问题是让后端改的接口返回值
解决方案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 的官方文档举例说明:
于是我们可以提取出关键的两个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"'