Netflix Feign – 通过微服务传播状态和exception

我正在使用Netflix Feign将微服务A的一个操作调用到微服务B的其他操作,该操作使用Spring Bootvalidation代码。

如果validation不好,微服务B的操作会抛出exception。 然后我在微服务中处理并返回一个HttpStatus.UNPROCESSABLE_ENTITY (422),如下所示:

 @ExceptionHandler({ ValidateException.class }) @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) @ResponseBody public Object validationException(final HttpServletRequest request, final validateException exception) { log.error(exception.getMessage(), exception); error.setErrorMessage(exception.getMessage()); error.setErrorCode(exception.getCode().toString()); return error; } 

因此,当微服务A在接口中调用B作为下一个:

 @Headers("Content-Type: " + MediaType.APPLICATION_JSON_UTF8_VALUE) @RequestLine("GET /other") void otherOperation(@Param("other") String other ); @Headers("Content-Type: " + MediaType.APPLICATION_JSON_UTF8_VALUE) @RequestLine("GET /code/validate") Boolean validate(@Param("prefix") String prefix); static PromotionClient connect() { return Feign.builder() .encoder(new GsonEncoder()) .decoder(new GsonDecoder()) .target(PromotionClient.class, Urls.SERVICE_URL.toString()); } 

并且validation失败它返回内部错误500并显示下一条消息:

 { "timestamp": "2016-08-05T09:17:49.939+0000", "status": 500, "error": "Internal Server Error", "exception": "feign.FeignException", "message": "status 422 reading Client#validate(String); content:\n{\r\n \"errorCode\" : \"VALIDATION_EXISTS\",\r\n \"errorMessage\" : \"Code already exists.\"\r\n}", "path": "/code/validate" } 

但我需要返回与微服务操作B相同的操作。

使用Netflix Feign通过微服务传播状态和例外的最佳方法或技术是什么?

你可以使用假装ErrorDecoder

https://github.com/OpenFeign/feign/wiki/Custom-error-handling

这是一个例子

 public class MyErrorDecoder implements ErrorDecoder { private final ErrorDecoder defaultErrorDecoder = new Default(); @Override public Exception decode(String methodKey, Response response) { if (response.status() >= 400 && response.status() <= 499) { return new MyBadRequestException(); } return defaultErrorDecoder.decode(methodKey, response); } } 

要使spring获取ErrorDecoder,您必须将它放在ApplicationContext上:

 @Bean public MyErrorDecoder myErrorDecoder() { return new MyErrorDecoder(); } 

我做的一个小库的无耻插件使用reflection来动态地重新抛出已检查的exception(如果它们在Feign界面上,则取消选中),这是基于响应正文中返回的错误代码。

有关自述文件的更多信息: https : //github.com/coveo/feign-error-decoder

编写自定义exception映射器并进行注册。 您可以自定义回复。

完整的例子在这里

 public class GenericExceptionMapper implements ExceptionMapper { @Override public Response toResponse(Throwable ex) { return Response.status(500).entity(YOUR_RETURN_OBJ_HERE).build(); } } 

我们做的是如下:

与两个微服务共享包含exception的公共jar。

1.)在微服务中将exception转换为DTO类可以说是ErrorInfo。 其中包含自定义exception的所有属性,其中包含一个String exceptionType,它将包含exception类名。

2.)当它在微服务B上接收时,它将由微服务B中的ErrorDecoder处理,它将尝试从exceptionType创建一个exception对象,如下所示:

 @Override public Exception decode(String methodKey, Response response) { ErrorInfo errorInfo = objectMapper.readValue(details, ErrorInfo.class); Class exceptionClass; Exception decodedException; try { exceptionClass = Class.forName(errorInfo.getExceptionType()); decodedException = (Exception) exceptionClass.newInstance(); return decodedException; } catch (ClassNotFoundException e) { return new PlatformExecutionException(details, errorInfo); } return defaultErrorDecoder.decode(methodKey, response); }