"三年前项目刚搭建时,我就提出过:JS的Number.MAX_SAFE_INTEGER(2^53-1)
就是颗定时炸弹,ID建议传输给前端之前格式化为字符串类型。
结果后端大佬们坚持说:'我们Java Long随便传、我们生成的ID就是数字、我们不会有那么多数据',现在用户量剧增,ID突破js最大安全范围,前端拿到的ID超出位全变成了000000这样的鬼样子!"
运维:"接口全炸了!"
产品:"用户投诉页面报错!"
后端(推眼镜):"这是前端精度问题,你们自己处理下,我返回的没问题啊"
「类型」:Java 中的 long
是一个 「有符号的 64 位整数」(signed 64-bit integer)。
「存储方式」:Java 的 long
类型使用 「补码表示法」(two's complement)来表示整数,这是一种在计算机中常用的表示有符号整数的方法。补码表示允许负数和正数使用相同的空间表示。
「数值范围」:
2^63 - 1 = 9,223,372,036,854,775,807
-2^63 = -9,223,372,036,854,775,808
Java 的 long
类型直接表示 64 位的有符号整数,不存在精度丧失问题,能够表示范围非常大的整数。
「类型」:JavaScript 中的 Number
是基于 「IEEE 754 双精度浮点数标准(64-bit double-precision floating point)」 。这个标准用于表示浮动小数点数,并且包含了整数和小数部分。
「存储方式」:JavaScript 的 Number
类型使用 「64 位浮点数」格式来存储数据。64 位格式中的 1 位用于符号位,11 位用于指数部分,剩下的 52 位用于尾数(即有效数字的表示)。这种存储方式使得它不仅可以表示整数,还可以表示小数。
Number
类型只能精确表示最大为 2^53 - 1
的整数。当数字大于 2^53 - 1
时,它会失去精度,因为有效数字超过了尾数的表示范围。「数值范围」:
JavaScript Number
类型支持更广泛的数值范围(包括小数),但由于尾数位数的限制,它无法精确表示所有的整数。
2^53 - 1 = 9,007,199,254,740,991
(即 Number.MAX_SAFE_INTEGER
)。-(2^53 - 1) = -9,007,199,254,740,991
(即 Number.MIN_SAFE_INTEGER
)。「Java long
类型」:是一个 「64 位有符号整数」,用于表示整数,范围从 -2^63
到 2^63 - 1
,精度上没有问题。
「JavaScript Number
类型」:是一个 「64 位双精度浮点数」,能够表示非常大的数,但由于其尾数部分的限制,「最大安全整数」为 2^53 - 1
,超过这个值会发生精度丧失。
因此,尽管两者都使用了 64 位的存储空间,它们的使用场景和内部实现差异导致了它们在精度和表示范围上的不同,就会出现在java
中合法的数字在js
中超出安全范围,导致精度丢失。
虽然正确的做法应该是后端用String传输,但既然要背锅,只能硬着头皮解决:
「transformResponse」
在大多数 Axios
封装的请求方法中,前端接收到后端响应的JSON体中,超长数字由于是字符串格式,所以未丢失精度。虽然 Axios
会自动解析响应数据,但你仍然可以在 「transformResponse
」 中手动处理这种情况,确保接收到的数据不会丢失精度。
例如,在 Axios 请求响应的过程中,你可以拦截并将数字类型的 ID 转换成字符串,或者使用 BigInt
进行转换,也可以使用第三方库 json-bigint
统一处理响应体中所有大数。
// 导入 json-bigint
const JSONbig = require('json-bigint');
// 创建 axios 实例并配置 transformResponse
const axiosInstance = axios.create({
transformResponse: [(data) => {
// 使用 json-bigint 解析响应数据,避免精度丢失
if (data) {
return JSONbig.parse(JSON.stringify(data)); // 先转为 JSON 字符串再解析
}
return data;
}]
});
// 发起请求
axiosInstance.get('/api/your-api')
.then(response => {
// 直接获取 id,已处理为 BigInt 类型
console.log(response.data.id);
})
.catch(error => {
console.error(error);
});
"到底是技术无知,还是态度问题?当生产事故发生时,我们真的还要继续玩'前端背锅部'的老梗吗?"
欢迎大家访问我们的刷题网站(https://fe.ecool.fun/)或者小程序 前端面试题宝典 进行刷题,1200多道全网最全的前端面试题,让你一网打尽。近期还有会员卡免费领,全场打折的活动不容错过!刷题会员周卡免费送
有会员购买、辅导咨询的小伙伴,可以通过下面的二维码,联系我们的小助手。