问题:
跨项目内部调用的时候,如果返回值是字符串,则被调用方产生的businessException,不会被抛出来, 而是被直接解析为字符串,导致真实失败原因被隐藏
暂时解决方案1:
跨项目调用使用feigh,
1、被调用方业务异常返回500,并附加业务异常的header信息,此时gateway对外的返回会受到影响,通过header信息判断是业务异常,直接返回200进行处理
2、调用方自定义feigh对错误的解码器: CustomErrorDecoder把错误值转化为异常抛出来
解决方案2:
定义FeignClientResponseInterceptor拦截器进行处理
public FeignClientResponseInterceptor(ObjectFactory<HttpMessageConverters> messageConverters) {
super(messageConverters);
}
@Override
public Object decode(final Response response, Type type) throws IOException, FeignException {
String context = IOUtils.toString(response.body().asReader(StandardCharsets.UTF_8));
// 处理逻辑
// 此处重新构建 resposne,否则无法读取到返回值内容 Attempted read from closed stream.
return super.decode(response.toBuilder().body(context, StandardCharsets.UTF_8).build(), type);
}
拦截并抛出exception后会自动转化为decodeException,需要对decodeException再做处理后进行返回
/***
* feignDecode异常拦截
* 用户处理调用子服务返回businessException的处理
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(value = DecodeException.class)
public ApiResponseData<Void> decodeExceptionHandler(HttpServletRequest req, DecodeException e) {
log.error("---decodeException Handler---Host {} invokes url {} ERROR: {}", req.getRemoteHost(),
req.getRequestURL(), e.getMessage(),e);
Throwable cause = e.getCause();
if ( cause instanceof BusinessException){
BusinessException be = (BusinessException)cause;
ApiResponseData<Void> errorResponse= new ApiResponseData<>();
errorResponse.setCode(be.getErrorCode() );
errorResponse.setMessage(e.getMessage());
errorResponse.setType(BusinessException.class.getSimpleName());
errorResponse.setTraceId(tracer.currentSpan().context().traceIdString());
return errorResponse;
}
return ApiResponseData.exception("ServletException",e,tracer.