
title: PetLumina 07 — 宠物管理升级与 JavaScript 大数精度修复date: 2026-05-27tags:PetLuminaJavaScript雪花IDJSON解析AI开发categories:项目实战description: 宠物管理功能全面升级的过程中发现并彻底解决 JavaScript 大数精度丢失问题。深入分析 Number.MAX_SAFE_INTEGER 限制、后端 Long→String 序列化、前端正则 JSON 解析方案。PetLumina 07 — 宠物管理升级与大数精度修复一个「数据对不上」的 bug引出了 JavaScript 大数精度丢失的经典问题。一、问题发现1.1 现象宠物详情页的数据一直显示不正确 — 通过 ID 查询宠物返回的却是另一个宠物的数据。1.2 排查过程// Store 中获取宠物constpetpets.value.find(pp.idid)console.log(p.id)// 1266893287734558720 ← 字符串console.log(id)// 1266893287734558700 ← 数字最后两位变了console.log(p.idid)// false — 类型和值都不等根因JavaScript 的Number.MAX_SAFE_INTEGER是2^53 - 1 900719925474099116 位而雪花 ID 是 19 位数字超出了安全范围。1.3 精度丢失发生在哪个环节// 后端返回的 JSON{id:1266893287734558720}// JavaScript JSON.parse 后JSON.parse({id: 1266893287734558720})// { id: 1266893287734558700 } ← 最后两位被截断了// Number.MAX_SAFE_INTEGER9007199254740991// 16 位1266893287734558720// 19 位 — 超出范围精度丢失发生在JSON.parse()阶段— 不是后端的问题不是网络传输的问题是 JavaScript 解析 JSON 时就把数字截断了。二、后端解决方案必要但不充分2.1 Long → String 序列化// config/JsonConfig.javaConfigurationpublicclassJsonConfig{BeanpublicJackson2ObjectMapperBuilderCustomizerjacksonCustomizer(){returnbuilder-{// Long 转 String 防止 JS 大数字精度丢失builder.serializerByType(Long.class,ToStringSerializer.instance);builder.serializerByType(Long.TYPE,ToStringSerializer.instance);// Date 全局格式化builder.simpleDateFormat(yyyy-MM-dd HH:mm:ss);};}}配置后后端返回的 JSON 变成{id:1266893287734558720}← 有引号了是字符串2.2 为什么后端配置不够如果JSON.parse()已经执行过了Axios 默认会自动解析数字已经被截断为1266893287734558700此时即使后端返回的是字符串前端拿到的也是截断后的数字。需要在JSON.parse()之前介入。三、前端解决方案3.1 正则预处理在JSON.parse()之前用正则将 16 位数字加上引号// api/request.ts/** * 处理 JSON 中超大数字的精度丢失问题 * 将超过安全整数范围的数字转为字符串 */functionparseJsonWithBigInt(jsonStr:string):any{constsafeStrjsonStr.replace(/(?:[^\\]|\\.)*|(-?\d{16,}(?:\.\d)?(?:[eE][-]?\d)?)/g,(match,num){if(num){return${num}// 数字加引号变成字符串}returnmatch// 字符串部分保持不变})returnJSON.parse(safeStr)}正则解析(?:[^\\]|\\.)* ← 匹配已有的字符串跳过不做处理 | ← 或 (-?\d{16,}(?:\.\d)?...) ← 匹配 16 位的数字转为字符串3.2 响应拦截器集成// api/request.tsrequest.interceptors.response.use((response){letres:anyif(typeofresponse.datastring){// 直接是字符串用自定义解析器try{resparseJsonWithBigInt(response.data)}catch{resresponse.data}}else{// Axios 已经 JSON.parse 过了大数字可能已丢失精度// 用原始文本重新解析constrawText(responseasany).request?.responseTextif(rawText){try{resparseJsonWithBigInt(rawText)}catch{resresponse.data}}else{resresponse.data}}// 业务逻辑处理if(res.code!0){showToast(res.message||请求失败)returnPromise.reject(newError(res.message))}returnres.data})关键使用response.request.responseText获取原始 JSON 文本在JSON.parse之前做正则替换。3.3 Store 中的 ID 比较// stores/user.tsconstgetPetById(id:string){// ❌ 错误 — 类型不匹配// return pets.value.find(p p.id id)// ✅ 正确 — 统一转为字符串比较returnpets.value.find(pString(p.id)String(id))}四、JsonConfig 的 Date 格式化同一个JsonConfig还配置了全局日期格式化builder.simpleDateFormat(yyyy-MM-dd HH:mm:ss);这样后端所有Date类型的字段都会序列化为2026-06-07 10:30:00格式前端不需要再做格式转换。五、完整的数据流后端 Entity 后端 JSON 前端 JSON.parse 前端使用 ───────────── ────────── ────────────── ────────── Long id id: 1266...720 parseJsonWithBigInt() String(id) 1266893287734558720 (Long→String 序列化) 正则替换后 parse 1266...720 Date createTime createTime: 2026-06... JSON.parse formatDate() Sat Jun 07 2026 (simpleDateFormat) 自动解析为字符串 2026-06-07...六、其他 ID 场景的处理大数精度问题不只出现在宠物 ID所有使用雪花 ID 的地方都要注意// 帖子详情constpostawaitpostApi.getDetail(route.params.idasstring)// 通知详情constnotificationawaitnotificationApi.getDetail(notificationId)// 路由参数 — :id 也是 stringrouter.push(/pet/${pet.id})七、总结v2.5 完成了宠物管理升级和大数精度修复。核心经验JavaScriptNumber.MAX_SAFE_INTEGER是 16 位— 雪花 ID 是 19 位必然精度丢失精度丢失发生在JSON.parse()阶段— 后端配置Long→String是必要的但不够正则预处理方案— 在JSON.parse之前将大数加引号转字符串ID 比较统一用String()—String(a) String(b)万无一失从一开始就用 string 定义 ID 类型— 如果在 Mock 阶段就用id: string后面会省很多事