我司后端用Java的long类型(能存超级大的数字,比如雪花ID),但传到前端后,JavaScript的number类型接不住这么大数字,导致末尾几位被吞,变成00000… 比如你看到ID从1234567890123456789变成了1234567890123450000。
为啥会这样?
- 后端(Java):long类型是64位整数,能精确表示超级大的数字(最高到19位数)
- 前端(JavaScript):number类型用的是64位浮点数,虽然也能存大数,但精确表示的安全整数范围只有16位(2^53-1)。超过这个位数,精度就丢了!
浏览器Network里看着是对的,但JS里拿到就是错的? 因为浏览器DevTools的Network显示的是原始响应字符串(还没被JS解析),而JS拿到后会自动用JSON.parse()转成对象,就在这一步精度丢失了!
前端自救方案(治标不治本,但能应急):
- 最优解:后端改返回string类型(从根源解决,但需要协调)
- 前端拦截处理:用axios的transformResponse + json-bigint库
- 关键:要在Axios解析JSON之前,手动用json-bigint处理原始响应字符串
- 注意:不能先转成JS对象再处理,那时已经丢精度了!
import axios from 'axios';
import JSONbig from 'json-bigint';
const axiosInstance = axios.create({
transformResponse: [function (data) {
// 这里data还是字符串!直接用json-bigint解析
return JSONbig.parse(data);
}]
});
血泪教训:
- 所有可能超过15位的ID(比如雪花ID、分布式ID),必须让后端返回string类型!
- 联调时一定要测试大ID(比如18位以上的)边界情况!
- 别再让前端背锅了!这明明是数据类型兼容的常识问题!
所以下次后端再说“我们ID就是数字”时,可以把这篇文章甩过去——不是前端菜,是科学道理就这样!
前端学点后端知识,尽量全栈,不要被人骂菜鸡了😭