java - 后备工厂无法处理 Feign 客户端中的自定义异常
问题描述
我的要求是访问从第一个服务抛出的自定义异常及其在第二个服务中的正文内容
到目前为止,我已经尝试了 2 件事,FallbackFactory 和 ErrorDecoder,其中只有 Fallback factory对我有用。错误解码器没有从其他服务抛出的异常消息。这是我在另一个问题中找到的示例代码:
将有 2 种服务:库存服务和产品服务
库存服务
InventoryController.java
@RestController
@RequestMapping("/inventories")
public class InventoryController {
private final ProductServiceClient productService;
public InventoryController(ProductServiceClient productService) {
super();
this.productService = productService;
}
@GetMapping
public ResponseEntity<?> companyInfo() {
return productService.hello();
}
}
ProductServiceClient.java
@FeignClient(name = "product-service", url = "http://localhost:9100", fallbackFactory = ProductServiceClientFallback.class)
public interface ProductServiceClient {
@GetMapping("/products")
ResponseEntity<?> hello();
}
@Component
class ProductServiceClientFallback implements FallbackFactory<ProductServiceClient> {
@Override
public ProductServiceClient create(Throwable cause) {
return new ProductServiceClient() {
@Override
public ResponseEntity<?> hello() {
System.out.println("hello!! fallback reason was " + cause.getMessage());
return ResponseEntity.ok().build();
}
};
}
}
产品服务
产品控制器.java
@RestController
@RequestMapping(value = "/products")
public class ProductController {
@GetMapping
public String hello() throws Exception {
if (true) {
throw new Exception("Service B Exception...");
}
return "Hello World";
}
}
ProductControllerAdvice.java
@RestControllerAdvice
public class ProductControllerAdvice {
@ExceptionHandler
public ResponseEntity<?> handleException(Exception exception) {
return new ResponseEntity<>("Caused due to : " + exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
因此,当在 Inventory 控制器中触发/inventories api 时,它会通过 Feign 客户端触发对产品服务的调用,在产品服务端,我会抛出一个带有消息的自定义异常,我必须在我的库存服务中访问该消息.
为了实现这一点,我已经实现了后备工厂,并且它在测试工作区中工作,因为我在库存服务的控制台中得到了这样的输出
hello!! fallback reason was status 500 reading ProductServiceClient#hello(); content:
Caused due to : Service B Exception...
但是,我的问题是,当我对正在处理的应用程序尝试类似的方法时,我没有收到异常消息,而是得到了这样的输出:
reached fallback on workflow side, reason: status 400 reading ProvisioningServiceProxy#executeOrderAction(Long,Long,String)
服务-A
测试服务A.java
@FeignClient( url = "/executeOrder", fallbackFactory = TestServiceAFallback.class )
public interface TestServiceA extends Serializable{
@PostMapping( value = "order/{requestId}/order/{orderId}/{command}" )
public ResponseEntity<ProcessInstanceVariable> executeOrderAction( @PathVariable( name = "command" ) String command );
}
引发自定义异常的Service-B
TestServiceBController.java
@PostMapping( value = /executeOrder )
public ResponseEntity<ProcessInstanceVariable> executeOrderAction( @PathVariable( value = "command" ) String command )
{ //switch code to check the command value and throw exception for one particular command
throw new ValidationException("validation exception from service B");
}
我也有一个建议,它处理验证异常,并且该类中有这样的方法
TestServiceBControllerAdvice.java
@ExceptionHandler( ValidationException.class )
public ResponseEntity<Object> handleValidationException( ValidationException ve )
{
return new ResponseEntity<>( ve.getMessage(), HttpStatus.BAD_REQUEST );
}
所以,我期待在 TestServiceA 端收到我从 TestServiceB 发送的消息,但我收到一条通用消息,显示在读取 API 时 BAD REQUEST。
除了以下配置,我不确定 TestServiceA 端是否需要任何额外的配置:
testServiceA.properties
feign.hystrix.enabled=true
让我知道我是否遗漏了任何东西,我已经阅读了这个文档,在我看来,我已经按照它应该发生的方式完成了实现,以获取从其他服务抛出的消息和异常主体。
解决方案
对于任何来这个问题寻找答案的人,我最终都实现了 ErrorDecoder,它帮助我捕获了错误。细节对我来说有点褪色,消息是如何被捕获的。但我使用了以下代码:
public class CustomExceptionDecoder implements feign.codec.ErrorDecoder
{
@Override
public Exception decode( String methodKey,
Response response )
{
final ErrorDecoder defaultErrorDecoder = new Default();
try
{
if( response.body() != null )
{
byte[] bodyData = Util.toByteArray( response.body().asInputStream() );
String responseBody = new String( bodyData );
LOGGER.error( "Error captured in Custom Exception Decoder: ", responseBody );
return new CustomValidationException( responseBody );
}
}
catch( IOException e )
{
LOGGER.error( "Throwing IOException :: {}", e.getCause() );
}
return defaultErrorDecoder.decode( methodKey, response );
}
}
推荐阅读
- javascript - if/else 与 setInterval 自动刷新和点击刷新事件 jquery?
- javascript - 在下拉菜单中选择第一个选项作为默认选项
- python - Python FBX SDK – 如何缩放具有关键帧的模型?
- r - 我想删除 R 表中的多余行
- amazon-web-services - 从 s3 到 windows 服务器的 AWS 代码部署 EC2/本地 yml 文件错误
- c# - C#中的Assembly在哪里获取默认的程序集版本
- python - 有人可以解释以下关于 max() 的代码的输出吗?
- dart - Dart - 标记为已弃用的文档
- c++ - 我们如何在 C/C++ 程序中消除 break 语句以支持编译器进行自动向量化?
- python - 带有条件和关键字检查的字典理解