如何在返回类型不确定时调用FlurlHttpException.GetResponseJsonAsync?
关于FlurlHttpException.GetResponseJsonAsync类型不匹配的行为与兼容处理
类型不匹配时的行为
当调用ex.GetResponseJsonAsync<ErrorA>()但实际返回的是ErrorB的JSON结构时,默认会抛出反序列化异常:
- 若使用Flurl默认的Newtonsoft.Json序列化器,会抛出
JsonSerializationException - 若配置为System.Text.Json,则抛出
JsonException
不会自动生成带有默认属性的ErrorA对象,因为默认的反序列化规则要求JSON结构与目标类型匹配——比如ErrorB中不存在ErrorA的必填字段,或字段类型不匹配时,反序列化器会直接报错,而非填充默认值(除非你手动配置了序列化器的容错选项,比如忽略缺失属性、允许类型不匹配等,但这不是默认行为)。
兼容两种错误类型的处理方案
针对同一错误码可能返回两种不同错误结构的场景,推荐以下几种可靠的处理方式:
方案1:先读取原始JSON,判断结构后再反序列化
先将响应内容读取为字符串,解析成JObject(Newtonsoft)或JsonElement(System.Text.Json),通过特征字段判断实际类型:
// 先获取原始JSON字符串 var json = await ex.GetResponseStringAsync(); // 用Newtonsoft.Json解析 var jObj = JObject.Parse(json); ErrorBase error; // 根据特征字段区分类型(比如ErrorA有ErrorACode,ErrorB有ErrorBCode) if (jObj.ContainsKey("ErrorACode")) { error = jObj.ToObject<ErrorA>(); } else if (jObj.ContainsKey("ErrorBCode")) { error = jObj.ToObject<ErrorB>(); } else { throw new InvalidOperationException("未知的错误响应格式"); }
建议让ErrorA和ErrorB继承同一个基类ErrorBase,方便后续统一处理错误逻辑。
方案2:尝试反序列化第一种类型,失败则 fallback 到第二种
先尝试反序列化为ErrorA,捕获反序列化异常后再尝试ErrorB。注意要先读取JSON字符串,避免重复读取响应流导致的错误:
var json = await ex.GetResponseStringAsync(); ErrorBase error; try { // Newtonsoft.Json error = JsonConvert.DeserializeObject<ErrorA>(json); // 若用System.Text.Json则替换为: // error = JsonSerializer.Deserialize<ErrorA>(json); } catch (JsonSerializationException) // System.Text.Json用JsonException { try { error = JsonConvert.DeserializeObject<ErrorB>(json); } catch (JsonSerializationException) { throw new InvalidOperationException("无法解析错误响应格式"); } }
方案3:定义包含所有字段的联合类型
如果两种错误类型的字段无冲突,可以定义一个包含所有可能字段的联合类,反序列化后通过字段是否有值判断类型:
public class ErrorUnion { // ErrorA的字段 public string ErrorACode { get; set; } public string ErrorAMessage { get; set; } // ErrorB的字段 public int ErrorBCode { get; set; } public string ErrorBDetails { get; set; } } // 使用时 var errorUnion = await ex.GetResponseJsonAsync<ErrorUnion>(); if (!string.IsNullOrEmpty(errorUnion.ErrorACode)) { // 按ErrorA逻辑处理 } else if (errorUnion.ErrorBCode != 0) { // 按ErrorB逻辑处理 }
这种方式实现简单,但当字段较多或有冲突时不适用。
内容的提问来源于stack exchange,提问作者Alek Davis
相关产品推荐
相关产品推荐

