前后端传输 Long 类型数据时,精度丢失的根本原因是 JavaScript 的 Number 类型无法精确表示超过 53 位(64 位双精度浮点数)的整数,而 Java 的 Long 类型是 64 位整数。当后端返回的 Long 值超过 2^53-1
(即 9007199254740991
)时,前端解析会出现精度错误。
解决方案
方案一:后端将 Long 转为字符串(推荐)
后端修改(Spring Boot 示例):
局部方案:在字段上添加
@JsonFormat
注解public class UserDTO { @JsonFormat(shape = JsonFormat.Shape.STRING) private Long id; // 自动序列化为字符串 }
全局方案:配置 Jackson 序列化规则
@Configuration public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); // 所有 Long 类型转为字符串 builder.serializerByType(Long.class, ToStringSerializer.instance); return builder; } }
前端处理:
直接使用字符串类型的 ID,避免用 Number
类型解析:
javascript
// 正确:后端返回 { "id": "1234567890123456789" }
fetch('/api/user')
.then(res => res.json())
.then(data => {
const userId = data.id; // 直接作为字符串使用
console.log(userId); // "1234567890123456789"
});
方案二:前端特殊处理大整数
使用 JSON.parse 自定义解析(需确保后端不转字符串):
// 使用 json-bigint 库处理大整数
import JSONbig from 'json-bigint';
const response = await fetch('/api/data');
const text = await response.text();
const data = JSONbig.parse(text); // 自动将大数字转为 BigInt 类型
// 使用示例
console.log(data.id.toString()); // 转为字符串操作
方案三:后端使用 String 类型代替 Long
从根本上避免问题:
public class UserDTO {
private String id; // 直接定义为字符串类型
}
关键原因说明
类型 | 范围 | 精度限制 |
---|---|---|
Java Long | -9223372036854775808 ~ 9223372036854775807 |
64 位整数,无精度损失 |
JavaScript Number | ±9007199254740991 以内安全 |
超过 53 位丢失精度 |
最佳实践
优先推荐方案一:后端统一将 Long 序列化为字符串,前端按字符串处理。
若前端需数值运算:将字符串转为
BigInt
(注意浏览器兼容性):const bigIntId = BigInt("1234567890123456789"); // 字符串转BigInt
避免使用
Number()
或parseInt()
转换大数字符串,否则仍会丢失精度。
通过统一数据类型定义(字符串传输),可彻底解决此问题,同时保持数据精确性。