雪花ID本身是long,查了下json rfc,规范不限制范围,但说明了因为IEEE754广泛使用,[-(2**53)+1, (2**53)-1]范围内是可以互操作的,其他的可能会出问题,而这个可能会出问题就是实实在在的出问题了,前端直接接收到后端返回的long再回过来后,经度都会丢失。如后端给前端的是 1297873308628307970,而前端拿到返回回来则变成了12978733086283000000。
第一时间想到的是要把long改成字符串返回。
而场景大多数是系统写了一大批接口,突然发现有问题后,如果想回头改,解决方案可能就是改表或者改接口映射的DTO实体类,但这种改法吃力不讨好,工作量大容易出问题,数据库改成字符串查询性能又降低。
推荐做法就是在JSON解析器里面做处理,不同的解析器可能有不同的配置和重写方式,这里就按.net core webapi 的原始JSON解析改为NewtonsoftJSON后重写long类型解析来解决。
安装Microsoft.AspNetCore.Mvc.NewtonsoftJson
首先是安装Microsoft.AspNetCore.Mvc.NewtonsoftJson
修改默认JSON解析器
然后把webapi的默认JSON解析器改掉
services.AddControllers().AddNewtonsoftJson(options =>
{
//CustomContractResolver 是我们自定义的解析器
options.SerializerSettings.ContractResolver = new CustomContractResolver();
//修改时间的序列化方式
options.SerializerSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy/MM/dd HH:mm:ss" });
});
自定义long类型转换
public class CustomContractResolver : CamelCasePropertyNamesContractResolver
{
/ <summary>
/ 实现首字母小写
/ </summary>
/ <param name="propertyName"></param>
/ <returns></returns>
//protected override string ResolvePropertyName(string propertyName)
//{
// return propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
//}
/// <summary>
/// 对长整型做处理
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
protected override JsonConverter ResolveContractConverter(Type objectType)
{
if (objectType == typeof(long))
{
return new JsonConverterLong();
}
return base.ResolveContractConverter(objectType);
}
/ <summary>
/ Creates a Newtonsoft.Json.Serialization.JsonProperty for the given System.Reflection.MemberInfo.
/ </summary>
/ <param name="type"></param>
/ <param name="memberSerialization"></param>
/ <returns></returns>
//protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
//{
// return type.GetProperties()
// .Select(p =>
// {
// var jp = base.CreateProperty(p, memberSerialization);
// jp.ValueProvider = new NullToEmptyStringValueProvider(p);
// return jp;
// }).ToList();
//}
}
public class JsonConverterLong : JsonConverter
{
/// <summary>
/// 是否可以转换
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
public override bool CanConvert(Type objectType)
{
return true;
}
/// <summary>
/// 读json
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if ((reader.ValueType == null || reader.ValueType == typeof(long?)) && reader.Value == null)
{
return null;
}
else
{
long.TryParse(reader.Value != null ? reader.Value.ToString() : "", out long value);
return value;
}
}
/// <summary>
/// 写json
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
writer.WriteValue(value);
else
writer.WriteValue(value + "");
}
}
总结
这样就完成了,所有long类型的都会转化为字符串返回,而原有代码和数据结构逻辑无需改变,这样不管是不是雪花ID,其他类型是long产生的隐患也一并得以解决。