.NET Framework 4.7 WebAPI返回long类型值到Angular前端出现精度偏差
问题根因
你遇到的数值偏差确实是自动四舍五入(rounding)导致的,核心原因如下:
- JavaScript 内置的
Number类型为双精度64位浮点数,仅支持范围在[-9007199254740991, 9007199254740991](即 ±2^53-1)的安全整数,超出该范围的整数值无法被精确存储 - 本次出现偏差的数值
9997773333333335远大于2^53的上限,浏览器默认调用JSON.parse()解析接口返回的JSON时,会自动将超出精度的长整数四舍五入,最终就出现了+1的偏差 - 后端.NET的long类型、数据库Bigint类型本身支持64位整数的完整精度,因此后端调试、数据库存储的数值都是正常的,问题仅出在前后端数据传输后的JSON解析环节
解决方案
方案1:后端改造(优先推荐,兼容性最好)
直接将.NET接口返回对象中的long类型字段序列化为字符串输出,从根源避免前端精度丢失,操作方式可选择全局配置或单独字段配置:
全局配置(所有long类型自动转字符串)
在WebApiConfig的Register方法中添加序列化配置:
using Newtonsoft.Json; using Newtonsoft.Json.Converters; public static class WebApiConfig { public static void Register(HttpConfiguration config) { // 其他原有配置... // 配置long类型序列化为字符串 config.Formatters.JsonFormatter.SerializerSettings.Converters.Add( new CustomLongToStringConverter() ); } } // 自定义Long转String序列化转换器 public class CustomLongToStringConverter : JsonConverter<long> { public override void WriteJson(JsonWriter writer, long value, JsonSerializer serializer) { writer.WriteValue(value.ToString()); } public override long ReadJson(JsonReader reader, Type objectType, long existingValue, bool hasExistingValue, JsonSerializer serializer) { return long.Parse(reader.Value?.ToString() ?? "0"); } }
单独字段配置(仅指定long字段转字符串)
给DTO类中对应的long类型字段添加序列化特性即可:
public class YourResponseDto { [JsonConverter(typeof(StringConverter))] public long YourBigintField { get; set; } // 其他属性... }
方案2:前端改造(适合后端无法修改的场景)
不使用浏览器默认的JSON.parse解析响应,改用支持大整数的解析库处理,以json-bigint为例:
- 安装依赖
npm install json-bigint
- 在Angular的HTTP拦截器中自定义响应解析逻辑,将超出精度的长整数转为字符串存储:
import { Injectable } from '@angular/core'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; import JSONbig from 'json-bigint'; import { Observable, map } from 'rxjs'; @Injectable() export class BigIntParseInterceptor implements HttpInterceptor { private jsonBig = JSONbig({ storeAsString: true }); intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(req).pipe( map(event => { if (event instanceof HttpResponse && typeof event.body === 'string') { try { const parsedBody = this.jsonBig.parse(event.body); return event.clone({ body: parsedBody }); } catch (e) { return event; } } return event; }) ); } }
问题截图参考


内容的提问来源于stack exchange,提问作者Alonso Contreras
相关产品推荐
相关产品推荐

