后端Long型数据传到前端js后精度丢失的问题(前后端传输踩坑指南)

在全栈开发中,遇到过这样一个"诡异"的问题:

后端返回一个 Long 类型 ID,前端接收到后却变了值 😨

比如:

json 复制代码
{
  "id": 9007199254740993
}

前端 JS 打印出来却是:

javascript 复制代码
9007199254740992

这不是 bug,这是经典的精度丢失问题

出现这种问题,可以做一个测试:在浏览器的Network(网络)面板中,不要看Preview(预览)标签页,而是点开Response(响应/原始数据)标签页。你会发现,原始的纯文本字符串是正常的,但只要经过工具的"美化/格式化"它就会因为超出JS安全整数范围,被自动进位,进而改变数据呈现方式。

你用来查看接口返回数据的工具(比如浏览器的Network面板、Postman、Swagger 等),它们底层在格式化展示 JSON 时,也是用 JavaScript 解折的!


文章目录

    • 一、问题本质
      • [1. Java 的 Long 是什么?](#1. Java 的 Long 是什么?)
      • [2. JavaScript 的 Number 是什么?](#2. JavaScript 的 Number 是什么?)
      • [⚠️ 超过这个值会发生什么?](#⚠️ 超过这个值会发生什么?)
    • 二、典型场景
    • 三、解决方案
    • [方案一:后端转 String(最推荐 ⭐)](#方案一:后端转 String(最推荐 ⭐))
    • [方案二:前端使用 BigInt](#方案二:前端使用 BigInt)
    • [方案三:前端使用 JSON 解析库](#方案三:前端使用 JSON 解析库)
    • 不推荐方案
      • [方案:强行用 Number](#方案:强行用 Number)
    • [🧩 四、最佳实践总结](#🧩 四、最佳实践总结)
    • 参考

一、问题本质

1. Java 的 Long 是什么?

在 Java 中:

java 复制代码
Long.MAX_VALUE = 9223372036854775807

👉 64 位整数(long),精度完全没问题。


2. JavaScript 的 Number 是什么?

在 JavaScript 中:

  • 所有数字都是 Number
  • 基于 IEEE 754 双精度浮点数

👉 最大安全整数:

javascript 复制代码
Number.MAX_SAFE_INTEGER === 9007199254740991

⚠️ 超过这个值会发生什么?

javascript 复制代码
9007199254740991 + 1 === 9007199254740992 // ✅
9007199254740991 + 2 === 9007199254740992 // ❌ 精度丢失

👉 这就是为什么 Long 在 JS 中会"变"。


二、典型场景

后端返回

java 复制代码
@Data
public class User {
    private Long id;
}

接口返回:

json 复制代码
{
  "id": 9223372036854775807
}

前端接收

javascript 复制代码
console.log(res.id);
// 输出:9223372036854776000 ❌

👉 精度直接炸掉。


三、解决方案


方案一:后端转 String(最推荐 ⭐)

✔ 原理

👉 避免 JS 解析为 Number,直接作为字符串处理。


✔ 实现方式(Jackson)

使用 @JsonSerialize

java 复制代码
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

public class User {

    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;
}

全局配置(推荐)

java 复制代码
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
    return builder -> builder.serializerByType(Long.class, ToStringSerializer.class)
                             .serializerByType(Long.TYPE, ToStringSerializer.class);
}

返回结果

json 复制代码
{
  "id": "9223372036854775807"
}

前端处理

javascript 复制代码
const id = res.id; // string

👉 安全 ✅ 无损 ✅


方案二:前端使用 BigInt

适用场景

  • 需要参与计算
  • 不只是展示

示例

javascript 复制代码
const id = BigInt("9223372036854775807");
console.log(id + 1n);

⚠️ 注意

  • 必须加 n
  • 不能和普通 Number 混用
javascript 复制代码
1n + 1 // ❌ 报错

方案三:前端使用 JSON 解析库

比如:

  • json-bigint

地址:https://www.npmjs.com/package/json-bigint


示例

javascript 复制代码
import JSONbig from 'json-bigint';

const data = JSONbig.parse(responseText);

console.log(data.id.toString());

优点

  • 自动处理大整数
  • 不需要改后端

缺点

  • 增加依赖
  • 性能略低

不推荐方案

方案:强行用 Number

javascript 复制代码
parseInt(res.id)

👉 依然会丢精度,没意义。


🧩 四、最佳实践总结

方案 推荐指数 说明
后端转 String ⭐⭐⭐⭐⭐ 最稳定,最通用
BigInt ⭐⭐⭐⭐ 适合计算
json-bigint ⭐⭐⭐ 特殊场景
直接 Number 一定会出问题

参考

使用axios请求,前端数字long类型精度问题解决方法-CSDN博客

长得太长也是错?------后端 Long 型 ID 精度丢失的"奇妙"修复之旅-腾讯云开发者社区-腾讯云

解决后端Long型数据传到前端js后精度丢失的问题-知乎

相关推荐
Nanachi13 小时前
跨框架的前端源码定位,再加上点LLM
前端
程序员二叉13 小时前
【JUC】AQS底层深度拆解|独占/共享模式|队列原理全详解
java·开发语言·面试·juc
地铁潜行者13 小时前
消息堆积后,为什么一扩容消费者,MySQL 先被打崩了?
java·后端
地铁潜行者13 小时前
订单状态更新成功了,分账消息却没发出去:聊聊本地消息表的一致性坑
java·后端
亦暖筑序13 小时前
Java 8老系统SQL Agent实战:AI生成候选SQL,安全引擎拦截后再执行
java·人工智能·sql
CodeStats13 小时前
《源纹天书》卷一:归元初醒(第1-5章)
java
大囚长13 小时前
大模型服务端如何命中缓存
java·人工智能·缓存·dubbo
别叫我老干部13 小时前
一键给整个库造测试数据:外键、约束一个都不能少
后端·mysql
摇滚侠13 小时前
SpringMVC 入门到实战 拦截器 78-82
java·后端·spring·maven·intellij-idea
椰椰椰耶13 小时前
[SpringCloud][13]OpenFeign快速上手
后端·spring·spring cloud