Netflix Feign - 通过微服务传播状态和异常

新手上路,请多包涵

我正在使用 Netflix Feign 将微服务 A 的一个操作调用到微服务 B 的其他其他操作,后者使用 Spring Boot 验证代码。

如果验证失败,微服务 B 的操作将抛出异常。然后我在微服务中处理并返回 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());
}

并且验证失败,它返回一个内部错误 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 通过微服务传播状态和异常的最佳方法或技术是什么?

原文由 Pau 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 911
2 个回答

你可以使用假装 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();
}

原文由 Mathias Dpunkt 发布,翻译遵循 CC BY-SA 3.0 许可协议

OpenFeign 的 FeignException 不绑定到特定的 HTTP 状态(即不使用 Spring 的 @ResponseStatus 注释),这使得 Spring 默认为 500 每当遇到 FeignException 。这没关系,因为 FeignException 可能有许多与特定 HTTP 状态无关的原因。

但是,您可以更改 Spring 处理 FeignExceptions 的方式。只需定义一个 ExceptionHandler 来处理 FeignException 你需要的方式(见 这里):

 @RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(FeignException.class)
    public String handleFeignStatusException(FeignException e, HttpServletResponse response) {
        response.setStatus(e.status());
        return "feignError";
    }

}

此示例使 Spring 返回您从微服务 B 收到的相同 HTTP 状态。您可以更进一步,还返回原始响应主体:

 response.getOutputStream().write(e.content());

原文由 Moritz 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题