开发学院

您的位置:首页>技术文章>正文

技术文章

JAVA大整数传递给前端丢失精度问题解决指南

开发学院2026-03-26 08:24:54
JAVA项目中涉及到分布式 ID、雪花算法 ID等大整数,直接以数值方式传递给前端,超过16位会遇到数字末尾被清零或四舍五入的诡异现象

  JAVA项目中涉及到分布式 ID、雪花算法 ID等大整数,直接以数值方式传递给前端,超过16位会遇到数字末尾被清零或四舍五入的诡异现象:

// 明明赋值的是 1234567890123456789
const id = 1234567890123456789;
console.log(id); 
// 输出:1234567890123456800(最后几位变成了 00!)

// 或者 AJAX 请求获取后端数据
fetch('/api/order/1234567890123456789')
  .then(r => r.json())
  .then(data => {
    console.log(data.orderId); // 9876543210987654400(精度丢失)
  });

  这种现象在电商订单号、用户 ID、金融交易号等场景中尤为常见。

根本原因:IEEE 754 双精度限制

  JavaScript 的 Number 类型基于 IEEE 754 双精度浮点数标准,使用 64 位存储:

  符号位:1 位

  指数位:11 位

  尾数(有效数字):52 位

  这导致 Number 类型的安全整数范围仅为:

  Number.MAX_SAFE_INTEGER = 9007199254740991  // 即 2^53 - 1,共 16 位
  Number.MIN_SAFE_INTEGER = -9007199254740991

  超过这个范围的整数将失去精度:

console.log(Number.MAX_SAFE_INTEGER);     // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992(正确)
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992(错误!与上一行相同)

解决方案

  API 后端字符串化这是从根本上解决问题的最佳实践。 让后端将所有可能超过 16 位的大整数序列化为字符串返回。

// ❌ 错误:直接返回 Long 类型
@RestController
public class OrderController {
    @GetMapping("/order/{id}")
    public Long getOrderId(@PathVariable Long id) {
        return 1234567890123456789L; // 前端接收会丢失精度
    }
}

// ✅ 正确:返回 String 类型
@RestController
public class OrderController {
    @GetMapping("/order/{id}")
    public String getOrderId(@PathVariable Long id) {
        return "1234567890123456789"; // 前端安全接收
    }
}

// 或者使用 Jackson 注解(全局处理)
public class OrderVO {
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long orderId;
}

前端使用:

fetch('/api/order/123')
  .then(r => r.json())
  .then(data => {
    // data.orderId 是字符串 "1234567890123456789"
    console.log(data.orderId); // 安全使用
  });

  优点:零成本、兼容所有浏览器、无需额外处理。

  缺点:需要后端配合修改 API 契约。