JSON-RPC调用报400错误及NaN值问题排查求助
解决JSON-RPC响应序列化失败(错误/NaN结果)的问题
根据你描述的情况——运行指定源码时返回错误或NaN,手动构造响应类序列化仍无法得到期望的JSON结构,我梳理了几个常见的问题点和对应的解决方法,都是基于JsonRpc命名空间下的场景:
1. 先处理JSON不支持的NaN值
JSON规范本身并不支持NaN、Infinity这类特殊数值,多数序列化库(比如System.Text.Json、Newtonsoft.Json)遇到这些值时会直接抛出异常,或者输出不符合要求的内容,这是最常见的序列化失败原因。
解决方法:在计算result前先检查并替换特殊值,或者配置序列化器自动处理:
示例(System.Text.Json)
在JsonRpc命名空间下配置序列化选项,并添加自定义转换器处理NaN:
namespace JsonRpc { public static class RpcSerializer { public static JsonSerializerOptions GetOptions() { var options = new JsonSerializerOptions(); options.Converters.Add(new NaNToNullConverter()); return options; } } // 自定义转换器:将NaN/Infinity转换为null public class NaNToNullConverter : JsonConverter<double> { public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.GetDouble(); } public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) { if (double.IsNaN(value) || double.IsInfinity(value)) { writer.WriteNullValue(); } else { writer.WriteNumberValue(value); } } } }
示例(Newtonsoft.Json)
namespace JsonRpc { public static class RpcSerializer { public static JsonSerializerSettings GetSettings() { return new JsonSerializerSettings { Converters = new List<JsonConverter> { new NaNConverter() }, NullValueHandling = NullValueHandling.Ignore }; } } public class NaNConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(double) || objectType == typeof(float); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return reader.Value; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value is double d && (double.IsNaN(d) || double.IsInfinity(d))) { writer.WriteNull(); } else if (value is float f && (float.IsNaN(f) || float.IsInfinity(f))) { writer.WriteNull(); } else { writer.WriteValue(value); } } } }
2. 检查手动构造的响应类是否符合序列化要求
确保你的响应类属性权限、名称和期望的JSON结构完全匹配:
namespace JsonRpc { // 类和属性必须是public,序列化器才能访问 public class RpcResponse { // 用JsonPropertyName指定JSON字段名,避免大小写不匹配问题 [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("status")] public string Status { get; set; } [JsonPropertyName("type")] public string Type { get; set; } [JsonPropertyName("result")] public object Result { get; set; } // 构造函数快速初始化默认值 public RpcResponse(int requestId) { Id = requestId; Status = "success"; Type = "response"; Result = new {}; // 默认空对象 } } }
3. 统一错误捕获与响应构造
运行指定源码时可能抛出异常,导致无法正常构造响应。需要在执行逻辑外层添加try-catch,确保无论成功还是失败都返回符合格式的JSON:
namespace JsonRpc { public class RpcHandler { public string ExecuteSourceCode(int requestId, string sourceCode) { try { // 执行源码逻辑 var rawResult = RunUserSourceCode(sourceCode); // 清理结果中的特殊值 var cleanedResult = CleanSpecialValues(rawResult); // 构造成功响应 var response = new RpcResponse(requestId) { Result = cleanedResult }; return JsonSerializer.Serialize(response, RpcSerializer.GetOptions()); } catch (Exception ex) { // 构造错误响应(可根据需求调整错误内容) var errorResponse = new RpcResponse(requestId) { Status = "error", Result = new { errorMessage = ex.Message } }; return JsonSerializer.Serialize(errorResponse, RpcSerializer.GetOptions()); } } private object RunUserSourceCode(string sourceCode) { // 你的源码执行逻辑 } private object CleanSpecialValues(object result) { // 递归遍历结果,替换所有NaN/Infinity为合法值(比如null) // 针对字典、列表等复杂类型需要单独处理 } } }
4. 验证序列化输出
如果还是有问题,可以先将响应对象序列化后打印,检查格式是否符合预期:
var testResponse = new RpcResponse(1); var json = JsonSerializer.Serialize(testResponse, RpcSerializer.GetOptions()); Console.WriteLine(json); // 检查输出是否为:{"id":1,"status":"success","type":"response","result":{}}
内容的提问来源于stack exchange,提问作者Jitender
相关产品推荐
相关产品推荐

