前后端传输 Long 类型数据时(时间戳,雪花算法ID),精度丢失的根本原因

发布于:2025-05-30 ⋅ 阅读:(18) ⋅ 点赞:(0)

前后端传输 Long 类型数据时,精度丢失的根本原因是 JavaScript 的 Number 类型无法精确表示超过 53 位(64 位双精度浮点数)的整数,而 Java 的 Long 类型是 64 位整数。当后端返回的 Long 值超过 2^53-1(即 9007199254740991)时,前端解析会出现精度错误。

解决方案

方案一:后端将 Long 转为字符串(推荐)

后端修改(Spring Boot 示例)

  1. 局部方案:在字段上添加 @JsonFormat 注解

    public class UserDTO {
        @JsonFormat(shape = JsonFormat.Shape.STRING)
        private Long id; // 自动序列化为字符串
    }

  2. 全局方案:配置 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 位丢失精度

最佳实践

  1. 优先推荐方案一:后端统一将 Long 序列化为字符串,前端按字符串处理。

  2. 若前端需数值运算:将字符串转为 BigInt(注意浏览器兼容性):

    const bigIntId = BigInt("1234567890123456789"); // 字符串转BigInt
  3. 避免使用 Number() 或 parseInt() 转换大数字符串,否则仍会丢失精度。

通过统一数据类型定义(字符串传输),可彻底解决此问题,同时保持数据精确性。


网站公告

今日签到

点亮在社区的每一天
去签到