Можем ли мы сгенерировать исключение в fallback или fallbackFactory из @FeignClient - PullRequest
0 голосов
/ 07 января 2020

Я использую @FeignClient и хочу сделать несколько логов c (например, записать информацию об исключении), когда Feign выбрасывает Exception, а затем отправлять результат в интерфейс.

Я заметил, что Feign выбросит FeignException, когда не удается установить соединение или статус http не ожидается.

Поэтому я определил @ExceptionHandler для перехваченного FeignException после вызова метода обратного вызова.

    @ExceptionHandler(value = FeignException.class)
    @ResponseBody
    public ResponseResult feignException(FeignException exception){
        String message = exception.getMessage();
        byte[] content = exception.content();
        int status = exception.status();
        if(content!=null){
            String response=new String(content);
            message=String.format("%s response message : %s",message,response);
        }
        log.warn("{} : {} , cause by : {}",exception.getClass().getSimpleName(),message,exception.getCause());
        return ResponseResult.fail(HttpStatus.valueOf(status),String.format("9%s00",status),message);

Но он не может быть перехвачен, когда я установил callback или callbackFactory из @ FeignClient.

    @FeignClient(url = "${onboardingcase.uri}",name = "OnBoardingCaseService",
            fallbackFactory = OnBoardingCaseServiceFallBack.class)


@Component
@Slf4j
public class OnBoardingCaseServiceFallBack implements FallbackFactory<OnBoardingCaseService> {

    @Override
    public OnBoardingCaseService create(Throwable throwable) {
        return new OnBoardingCaseService() {
            @Override
            public OnBoardingCaseVo query(String coid) {

                if(throwable instanceof FeignException){
                    throw (FeignException)throwable;
                }
                return null;
            }
        };
    }
}

Я заметил, что Hystrix принял этот метод. И будет перехватывать исключения в HystrixInvocationHandler.

try {
                                Object fallback = HystrixInvocationHandler.this.fallbackFactory.create(this.getExecutionException());
                                Object result = ((Method)HystrixInvocationHandler.this.fallbackMethodMap.get(method)).invoke(fallback, args);
                                if (HystrixInvocationHandler.this.isReturnsHystrixCommand(method)) {
                                    return ((HystrixCommand)result).execute();
                                } else if (HystrixInvocationHandler.this.isReturnsObservable(method)) {
                                    return ((Observable)result).toBlocking().first();
                                } else if (HystrixInvocationHandler.this.isReturnsSingle(method)) {
                                    return ((Single)result).toObservable().toBlocking().first();
                                } else if (HystrixInvocationHandler.this.isReturnsCompletable(method)) {
                                    ((Completable)result).await();
                                    return null;
                                } else {
                                    return HystrixInvocationHandler.this.isReturnsCompletableFuture(method) ? ((Future)result).get() : result;
                                }
                            } catch (IllegalAccessException var3) {
                                throw new AssertionError(var3);
                            } catch (ExecutionException | InvocationTargetException var4) {
                                throw new AssertionError(var4.getCause());
                            } catch (InterruptedException var5) {
                                Thread.currentThread().interrupt();
                                throw new AssertionError(var5.getCause());
                            }

Так что я хочу знать, как я могу бросить исключение, когда я использую callback / callbackFactory или есть другой способ вместо callbackFactory сделать "обратный вызов"?

Большое спасибо

Ответы [ 2 ]

0 голосов
/ 13 января 2020

Я нашел решение этой проблемы.

public class OnBoardingCaseServiceFallBack implements FallbackFactory<OnBoardingCaseService> {

    @Override
    public OnBoardingCaseService create(Throwable throwable) {
        return new OnBoardingCaseService() {
            @Override
            public OnBoardingCaseVo query(String coid) {
                log.error("OnBoardingCaseService#query fallback , exception",throwable);
                if(throwable instanceof FeignException){
                    throw (FeignException)throwable;
                }

                return null;
            }
        };
    }
}

А затем перехватил HystrixRuntimeException и получил причину исключения в ExceptionHandler для получения realException, обернутого Hystrix.

    @ExceptionHandler(value = HystrixRuntimeException.class)
    @ResponseBody
    public ResponseResult hystrixRuntimeException(HystrixRuntimeException exception){
        Throwable fallbackException = exception.getFallbackException();
        Throwable assertError = fallbackException.getCause();
        Throwable realException = assertError.getCause();
        if(realException instanceof FeignException){
            FeignException feignException= (FeignException) realException;
            String message = feignException.getMessage();
            byte[] content = feignException.content();
            int status = feignException.status();
            if(content!=null){
                String response=new String(content);
                message=String.format("%s response message : %s",message,response);
            }
            return ResponseResult.fail(HttpStatus.valueOf(status),String.format("9%s00",status),message);
        }
        String message = exception.getMessage();
        log.warn("{} : {} , cause by : {}",exception.getClass().getSimpleName(),message,exception.getCause());
        return ResponseResult.fail(ResultCode.FAIL.httpStatus(),ResultCode.FAIL.code(),message);
    }

Но я не думаю, что это хороший способ ~

0 голосов
/ 09 января 2020

Я никогда не делал этого в качестве запасного варианта, я реализовал пользовательский класс декодера ошибок («CustomFeignErrorDecoder») и расширил feign.code c .ErrorDecoder , каждый раз, когда возникает ошибка, она приходит в этот класс .

В функция декодирования выдает пользовательское исключение и перехватывает его на уровне контроллера или сервиса, чтобы показать ваше сообщение внешнему интерфейсу.

Пример:

@Component
public class CustomFeignErrorDecoder implements ErrorDecoder {

   @Override
   public Exception decode(String methodKey, Response response) {
       throw new CustomFeignErrorDecoderException(methodKey +" response status "+ response.status() +" request "+ response.request()+ " method "+ response.request().httpMethod());
   }
}
...