Go语言处理JSON-RPC响应中随id动态变化的result字段schema解码问题
动态JSON-RPC批量响应解码方案(Go语言)
核心思路
利用Go标准库encoding/json的json.RawMessage类型延迟解析动态字段,先解析响应外层固定结构,再根据请求ID和返回结构的映射关系单独解析每个result字段。
具体实现步骤
1. 定义通用响应结构体
先把外层固定字段解析出来,result字段暂存为原始JSON字节,不做即时解析:
import "encoding/json" // JSONRPCError 统一JSON-RPC错误结构 type JSONRPCError struct { Code int `json:"code"` Message string `json:"message"` Data any `json:"data,omitempty"` } // JSONRPCResponse 通用响应外层结构 type JSONRPCResponse struct { ID string `json:"id"` Error *JSONRPCError `json:"error"` Result json.RawMessage `json:"result"` // 延迟解析的原始字节 }
2. 提前维护ID与返回结构的映射关系
你在构造批量请求时,天然知道每个请求ID对应的方法以及该方法返回的result结构,提前建立映射即可:
// 先定义各个方法对应的返回结构体 type Action1Result struct { Field1 string `json:"field1"` Field2 int `json:"field2"` } type Action2Result struct { Name string `json:"name"` Age int `json:"age"` } // 构造请求时同步建立ID到结果指针的映射 reqIDToResult := map[string]any{ "1": &Action1Result{}, // id=1的请求对应Action1Result结构 "2": &Action2Result{}, // id=2的请求对应Action2Result结构 }
3. 分层解析响应
先解析整个响应数组为通用结构切片,再遍历每个响应单独解析result:
// 假设respBody是HTTP响应的原始字节 var respList []JSONRPCResponse // 第一步:解析外层固定结构,不会处理result字段 if err := json.Unmarshal(respBody, &respList); err != nil { // 处理全局解析错误 panic(err) } // 第二步:逐个解析对应result for _, resp := range respList { // 优先处理RPC接口返回的错误 if resp.Error != nil { panic(resp.Error) } // 拿到对应ID的结果指针 resultPtr, ok := reqIDToResult[resp.ID] if !ok { // 处理未匹配到ID的异常情况 continue } // 把原始result字节解析到对应结构体 if err := json.Unmarshal(resp.Result, resultPtr); err != nil { panic(err) } } // 解析完成后直接使用对应结果即可 action1Res := reqIDToResult["1"].(*Action1Result) action2Res := reqIDToResult["2"].(*Action2Result)
注意事项
- 不要依赖响应的顺序匹配请求:JSON-RPC规范没有要求批量响应的顺序和请求顺序一致,必须通过ID字段匹配
- 如果不需要强类型校验,也可以直接把
result解析为map[string]any,但后续使用需要做类型断言,适合结构非常灵活的场景
内容的提问来源于stack exchange,提问作者ipStack
相关产品推荐
相关产品推荐

