[http-nio-28688-exec-5] [com.gaotu.course.center.webcommon.handler.GlobalExcepti...
🚨 错误信息
🤖 AI解决方案
Hystrix + Feign JSON 反序列化错误分析
1. 错误翻译
原文:
com.netflix.hystrix.exception.HystrixRuntimeException: ClazzTypeFeignClient#listAllByClazzTypeNumberList(ClazzTypeRequest) failed and no fallback available.
译文:
ClazzTypeFeignClient 的 listAllByClazzTypeNumberList 方法调用失败,且没有可用的降级处理机制。
原文:
com.alibaba.fastjson.JSONException: field null expect '[', but {, pos 1, line 1, column 2
译文:
FastJSON 解析异常:期望字段是数组(以 '[' 开头),但实际接收到的是对象(以 '{' 开头),位置在第1行第2列。
2. 原因分析
根本原因
错误位置
ClazzTypeFeignClient#listAllByClazzTypeNumberList(ClazzTypeRequest){ 字符,说明返回的是对象(如 {"code":500,...}),而不是数组3. 解决方案
方案一:修复 Feign Client 接口定义(推荐)
java
// 原接口(期望返回 List)
@FeignClient(name = "clazz-type-service")
public interface ClazzTypeFeignClient {
@PostMapping("/api/clazz-type/list")
List listAllByClazzTypeNumberList(@RequestBody ClazzTypeRequest request);
}// 修复为:返回统一响应对象
@FeignClient(name = "clazz-type-service")
public interface ClazzTypeFeignClient {
@PostMapping("/api/clazz-type/list")
ResponseWrapper> listAllByClazzTypeNumberList(@RequestBody ClazzTypeRequest request);
}
// 响应包装类
@Data
public class ResponseWrapper {
private Integer code;
private Boolean success;
private String msg;
private T data; // 实际数据
private String stackMessage;
}
方案二:自定义 Feign Decoder 处理响应
java
// 1. 创建自定义解码器
@Component
public class CustomFastJsonDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
// 先解析为 ResponseWrapper
ResponseWrapper> wrapper = JSON.parseObject(bodyStr, ResponseWrapper.class);
// 检查响应状态
if (!wrapper.getSuccess()) {
throw new RuntimeException("远程服务异常: " + wrapper.getMsg());
}
// 提取实际数据部分进行反序列化
String dataJson = JSON.toJSONString(wrapper.getData());
return JSON.parseObject(dataJson, type);
}
}// 2. 在 Feign Client 配置中使用自定义解码器
@FeignClient(
name = "clazz-type-service",
configuration = CustomFeignConfig.class
)
public interface ClazzTypeFeignClient {
// ...
}
方案三:添加 Hystrix 降级策略
java
@FeignClient(
name = "clazz-type-service",
fallback = ClazzTypeFeignClientFallback.class
)
public interface ClazzTypeFeignClient {
@PostMapping("/api/clazz-type/list")
ResponseWrapper> listAllByClazzTypeNumberList(@RequestBody ClazzTypeRequest request);
}// 降级实现
@Component
public class ClazzTypeFeignClientFallback implements ClazzTypeFeignClient {
@Override
public ResponseWrapper> listAllByClazzTypeNumberList(ClazzTypeRequest request) {
// 返回默认值或空列表,避免级联故障
ResponseWrapper> wrapper = new ResponseWrapper<>();
wrapper.setCode(200);
wrapper.setSuccess(true);
wrapper.setMsg("服务降级返回");
wrapper.setData(Collections.emptyList());
return wrapper;
}
}
4. ️ 预防措施
️ 最佳实践建议
- 所有 Feign 接口统一使用
ResponseWrapper 包装响应- 避免直接返回
List 或基础类型yaml
# application.yml 配置
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
circuitBreaker:
requestVolumeThreshold: 20
sleepWindowInMilliseconds: 5000
开发工具推荐
java
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}