ASP.NET Core WebApi接口Ajax调用返回异常重复ID值问题求助
问题原因分析
这个问题的核心是JavaScript的Number类型精度限制导致的:
- JavaScript里的
Number是64位浮点数,它能精确表示的最大整数是2^53 - 1(也就是9007199254740991) - 你定义的
Id值(比如13060000000000039)已经远远超出了这个安全范围,当JSON序列化后的字符串被前端解析为JavaScript对象时,这些超大整数会被自动近似为最接近的可表示的Number值,最终出现所有ID被截断为同一个值的情况 - 而
load方法只是直接把接口返回的文本内容渲染到页面,没有将其解析为JavaScript对象,所以能看到正确的原始字符串,不会出现精度丢失
解决方案
根据你的场景,有几种可行的解决方式:
方案1:修改实体类,将Id改为字符串类型
直接把Invoice类的Id属性类型从long改为string,这样序列化后就是字符串,前端解析时不会有精度问题:
public class Invoice { public string Id { get; set; } public decimal Total { get; set; } }
然后在构造数据的时候把数值转成字符串:
var paid = new List<Invoice> { new Invoice {Id = "13060000000000039", Total = 10}, new Invoice {Id = "13060000000000040", Total = 20}, new Invoice {Id = "13060000000000041", Total = 30} };
方案2:配置Newtonsoft.Json将long类型序列化为字符串
如果你不想修改实体类的类型,可以在JSON序列化配置里指定把long类型转成字符串,这样前端拿到的就是字符串格式的ID:
在ConfigureServices里修改NewtonsoftJson的配置:
services.AddMvc().AddNewtonsoftJson(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 添加自定义转换器,将long转成字符串 options.SerializerSettings.Converters.Add(new Newtonsoft.Json.JsonConverter<long>() { WriteJson = (writer, value, serializer) => writer.WriteValue(value.ToString()), ReadJson = (reader, objectType, existingValue, hasExistingValue, serializer) => long.Parse(reader.Value.ToString()) }); });
这样不需要修改实体类,序列化后的long类型会自动变成字符串,前端解析后就能保留完整的ID值。
方案3:前端使用BigInt处理超大整数
如果后端不想做任何修改,也可以在前端解析JSON的时候使用JSON.parse的第二个参数,把超大整数转成BigInt:
function getCallback(responseText) { // 手动解析响应文本,将超大整数转为BigInt const response = JSON.parse(responseText, (key, value) => { if (typeof value === 'number' && !Number.isSafeInteger(value)) { return BigInt(value); } return value; }); console.log(response); }
不过这种方式需要修改前端的请求逻辑,不让jQuery自动解析JSON,比如把dataType设置为text:
$.ajax({ type: "GET", url: "@Url.RouteUrl("NetApi", new {controller = "PurchasePayment", action = "Search", id = 26000000000000228})", contentType: "application/json; charset=utf-8", dataType: "text", // 改为text,不让jQuery自动解析 success: getCallback });
验证说明
修改后,前端拿到的JSON里的ID会是字符串或者BigInt类型,不会再出现精度丢失导致的重复问题,和你预期的结果一致。
内容的提问来源于stack exchange,提问作者Shadi Fayed
相关产品推荐
相关产品推荐

