问题
FeignClient接口调用异常时,默认会在接口原始异常信息基础上包装一层Feign Request信息:
code: -1
message: "[401 ] during [POST] to [http://uaa-center-server/oauth/token?grant_type=pin_code&username=sujingjun%40dhgate.com&password=liangb1231aaa&userType=1&verificationCode=0ee3674f07a7e3c7c3d87b4fb779afe3dq] [UaaServerClient#postAccessToken(String,String,String,Integer,String)]: [{"success":false,"code":401,"message":"username or password error."}]"
success: false
业务系统无法通过异常类的不能直接在异常信息中看出原始方法抛出的异常,需要做异常字符串截取等处理。Feign封装过的异常,不能直接在异常信息中看出原始方法抛出的异常。当调用服务时,如果服务返回的状态码不是200,就会进入到Feign的ErrorDecoder中,因此如果我们要解析异常信息,就要重写ErrorDecoder:
解决方案
- 在configuration中自定义ErrorDecoder
@Slf4j
@Configuration
public class FeignConfiguration implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
template.header("Authorization", "Basic ZGhnYXRlOnBwMTIz");
/* ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
template.header(name, values);
}
}*/
}
@Bean
public ErrorDecoder errorDecoder() {
return new UserErrorDecoder();
}
/**
* 自定义错误
*/
public class UserErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
Exception exception = null;
try {
// 获取原始的返回内容
String json = Util.toString(response.body().asReader(Charset.defaultCharset()));
exception = new RuntimeException(json);
// 将返回内容反序列化为Result,这里应根据自身项目作修改
Result result = JsonMapper.nonEmptyMapper().fromJson(json, Result.class);
// 业务异常抛出简单的 RuntimeException,保留原来错误信息
if (!result.getSuccess()) {
exception = new BusinessException(result.getMessage());
}
} catch (IOException ex) {
log.error(ex.getMessage(), ex);
}
return exception;
}
}
}
2.在Feign中@FeignClient注解中指定 configuration
@FeignClient(name = ServiceNameConstants.UAA_SERVER, configuration = {FeignConfiguration.class, FeignLogConfiguration.class})
public interface UaaServerClient {
使用自定义ErrorDecoder处理,后结果:
2020-09-12 19:04:00.055 ERROR[http-nio-7004-exec-3]com.dhgate.saas.ds.user.controller.UserController.LoginIfAbsentRegister:274 -自动登陆失败: username or password error.
2020-09-12 19:04:00.056 ERROR[http-nio-7004-exec-3]c.d.saas.common.core.exception.DefaultExceptionAdvice.defHandler:185 -username or password error.
com.dhgate.saas.common.core.exception.BusinessException: username or password error.
at com.dhgate.saas.ds.user.feign.FeignConfiguration$UserErrorDecoder.decode(FeignConfiguration.java:62)
at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96)