精华内容
下载资源
问答
  • feign自定义fallback方法

    千次阅读 2018-05-21 21:07:28
    在服务器值开启client端的情况下,会因为不能调用service端而去调用自定义调用失败的方法.这里需要注意的是,feign在后期的版本里面自带hystrix和ribbon的.这里需要在配置文件中把hystrix开启然后这个回调方法才会生效...

    client端的controller

    @RestController
    public class HelloWorldController {
    
      @Autowired
      private ServerFeignClient serverFeignClient;
    
      @GetMapping("/hello")
      public BaseResult<String> hello(){
          System.out.println("aaaaa");
          System.out.println("--------");
        return serverFeignClient.hello();
      }
    }

    client端的interface

    @FeignClient(name = "ZONESEA-SERVER-WZSC" , fallbackFactory = ServerFeignClientFallBackFactory.class )
    public interface ServerFeignClient {
    
      @RequestMapping(value = "/hello", method = RequestMethod.GET)
      BaseResult<String> hello();
    }

    client端调用失败的具体方法

    @Component
    public class ServerFeignClientFallBackFactory implements FallbackFactory<ServerFeignClient> {
    
      @Override
      public ServerFeignClient create(Throwable throwable) {
        return new ServerFeignClient() {
          @Override
          public BaseResult<String> hello() {
            BaseResult<String> baseResult =  new BaseResult<>();
            baseResult.setCode(-1);
            baseResult.setMessage("fail");
            return baseResult;
          }
        };
      }
    }

    在服务器值开启client端的情况下,会因为不能调用service端而去调用自定义调用失败的方法.这里需要注意的是,feign在后期的版本里面自带hystrix和ribbon的.这里需要在配置文件中把hystrix开启然后这个回调方法才会生效的.

    #开启hystrix配置
    feign:
      hystrix:
        enabled: true
    展开全文
  • feign自定义fallback调用出错

    千次阅读 2018-05-29 23:39:49
    feign的client端调用service端,在调用到service端的时候还会去执行自定义fallback可能有两种情况::一种是在执行service的时候报错,另外一种是调用service端的时候超时.调用service端的时候默认的请求时间为1秒,...

    feign的client端调用service端,在调用到service端的时候还会去执行自定义的fallback可能有两种情况::一种是在执行service的时候报错,另外一种是调用service端的时候超时.调用service端的时候默认的请求时间为1秒,超过这个时间便超时异常.
    1、把时间设长

    
    hystrix:
      command:
          default:
            execution:
              isolation:
                thread:
                  timeoutInMilliseconds: 5000
    

    2、把超时发生异常属性关闭

    hystrix:
      command:
          default:
            execution:
              timeout:
                enabled: false

    3、禁用feign的hystrix

    
    feign:
      hystrix:
        enabled: false

    原文博客地址:https://blog.csdn.net/qwlzxx/article/details/77163268

    展开全文
  • 目录Feign自定义ErrorDecoder错误时返回统一结构背景问题解决自定义FeignErrorDecoder在FeignCliet中使用FeignErrorDecoder自定义DefaultErrorAttributes全局异常统一处理[gateway]自定义ErrorHandlerConfiguration...

    背景

    微服务架构项目开发中,API接口都统一使用响应结构。
    http状态码统一返回200,状态码根据结构体的code获取。

    {
      "code": 0,
      "message": "success",
      "data": {
        "name": "kent"
      }
    }
    

    用户请求时,服务调用流程。
    用户请求时,服务调用流程

    问题

    微服务架构中,在正常的情况下,返回的数据结构是按照响应结构体返回的,但服务调用发生异常时,却返回不了code。
    例子,在order-service调用product-service,由于库存不足,抛出异常,返回的结果如下:

    {
      "timestamp": "2020-08-11 13:25:03", 
      "status": 500, 
      "error": "Internal Server Error",
      "exception": "tech.xproject.common.core.exception.BusinessException",
      "message": "not enough stock", 
      "trace": "tech.xproject.common.core.exception.BusinessException: not enough stock"
    }
    

    解决

    自定义FeignErrorDecoderDefaultErrorAttributesBusinessException对异常进行处理。

    自定义FeignErrorDecoder

    代码位置:service-api

    package tech.xproject.order.config;
    
    import com.alibaba.fastjson.JSON;
    import feign.FeignException;
    import feign.Response;
    import feign.RetryableException;
    import feign.codec.ErrorDecoder;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.annotation.Configuration;
    import tech.xproject.common.core.entity.ExceptionInfo;
    import tech.xproject.common.core.enums.ResultCodeEnum;
    import tech.xproject.common.core.exception.BusinessException;
    
    import java.nio.ByteBuffer;
    import java.nio.charset.StandardCharsets;
    import java.util.Optional;
    
    /**
     * @author kent
     */
    @Slf4j
    @Configuration
    public class FeignErrorDecoder extends ErrorDecoder.Default {
    
        @Override
        public Exception decode(String methodKey, Response response) {
            Exception exception = super.decode(methodKey, response);
    
            // 如果是RetryableException,则返回继续重试
            if (exception instanceof RetryableException) {
                return exception;
            }
    
            try {
                // 如果是FeignException,则对其进行处理,并抛出BusinessException
                if (exception instanceof FeignException && ((FeignException) exception).responseBody().isPresent()) {
                    ByteBuffer responseBody = ((FeignException) exception).responseBody().get();
                    String bodyText = StandardCharsets.UTF_8.newDecoder().decode(responseBody.asReadOnlyBuffer()).toString();
                    // 将异常信息,转换为ExceptionInfo对象
                    ExceptionInfo exceptionInfo = JSON.parseObject(bodyText, ExceptionInfo.class);
                    // 如果excepiton中code不为空,则使用该code,否则使用默认的错误code
                    Integer code = Optional.ofNullable(exceptionInfo.getCode()).orElse(ResultCodeEnum.ERROR.getCode());
                    // 如果excepiton中message不为空,则使用该message,否则使用默认的错误message
                    String message = Optional.ofNullable(exceptionInfo.getMessage()).orElse(ResultCodeEnum.ERROR.getMessage());
                    return new BusinessException(code, message);
                }
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
            return exception;
        }
    }
    

    在FeignClient中使用FeignErrorDecoder

    代码位置:service-api

    @FeignClient(name = ServiceNameConstant.ORDER_SERVICE, configuration = {FeignErrorDecoder.class})
    

    完整代码示例

    package tech.xproject.order.feign;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import tech.xproject.common.core.constant.ServiceNameConstant;
    import tech.xproject.order.config.FeignErrorDecoder;
    import tech.xproject.order.pojo.dto.CreateOrderReqDTO;
    import tech.xproject.order.pojo.entity.Order;
    
    /**
     * @author kent
     */
    @FeignClient(name = ServiceNameConstant.ORDER_SERVICE, configuration = {FeignErrorDecoder.class})
    public interface RemoteOrderService {
    
        /**
         * 创建订单
         *
         * @param createOrderReqDTO createOrderReqDTO
         * @return Order
         */
        @PostMapping("/order/create")
        Order create(@RequestBody CreateOrderReqDTO createOrderReqDTO);
    }
    
    

    自定义DefaultErrorAttributes

    代码位置:service
    若不自定义DefaultErrorAttributes,在返回时并不会带上code,需要将自定义的参数加入返回的对象中

    package tech.xproject.product.handler;
    
    import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.WebRequest;
    import tech.xproject.common.core.exception.BusinessException;
    
    import java.util.Map;
    
    /**
     * @author kent
     */
    @Component
    @Primary
    public class CustomErrorAttributes extends DefaultErrorAttributes {
    
        @Override
        public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
            Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
            Throwable error = this.getError(webRequest);
            if (error instanceof BusinessException) {
                errorAttributes.put("code", ((BusinessException) error).getCode());
            }
            return errorAttributes;
        }
    }
    
    

    全局异常统一处理

    代码位置:web

    package tech.xproject.web.manager.handler;
    
    import feign.FeignException;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.validation.BindException;
    import org.springframework.validation.FieldError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import tech.xproject.common.core.entity.R;
    import tech.xproject.common.core.enums.ResultCodeEnum;
    import tech.xproject.common.core.exception.BusinessException;
    
    import java.util.List;
    
    /**
     * @author kent
     */
    @Slf4j
    @RestControllerAdvice
    public class WebGlobalExceptionHandler {
    
        @ExceptionHandler({FeignException.class})
        @ResponseBody
        public R<?> feignExceptionHandler(FeignException exception) {
            log.error(exception.getMessage(), exception);
            return R.error(exception.getMessage());
        }
    
        @ExceptionHandler({RuntimeException.class})
        @ResponseBody
        public R<?> runtimeExceptionHandler(RuntimeException exception) {
            log.error(exception.getMessage(), exception);
            return R.error(exception.getMessage());
        }
    
        @ExceptionHandler({Exception.class})
        @ResponseBody
        public R<?> exceptionHandler(Exception exception) {
            log.error(exception.getMessage(), exception);
            return R.error(exception.getMessage());
        }
    
        @ExceptionHandler({BusinessException.class})
        public R<?> businessExceptionHandler(BusinessException exception) {
            log.error(exception.getMessage(), exception);
            return R.error(exception.getCode(), exception.getMessage());
        }
    
        @ExceptionHandler({BindException.class})
        @ResponseBody
        public R<?> bindExceptionHandler(BindException exception) {
            List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
            String errorMessage = fieldErrors.get(0).getDefaultMessage();
            log.error(errorMessage, exception);
            return R.error(ResultCodeEnum.ERROR_PARAMETER.getCode(), errorMessage);
        }
    
        @ExceptionHandler({MethodArgumentNotValidException.class})
        public R<?> validateExceptionHandler(MethodArgumentNotValidException exception) {
            List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
            String errorMessage = fieldErrors.get(0).getDefaultMessage();
            log.error(errorMessage, exception);
            return R.error(ResultCodeEnum.ERROR_PARAMETER.getCode(), errorMessage);
        }
    }
    
    

    [gateway]自定义ErrorHandlerConfiguration

    代码位置:gateway

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
        // 自定义Json异常处理
        JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes,
                this.resourceProperties, this.serverProperties.getError(), this.applicationContext);
        exceptionHandler.setViewResolvers(this.viewResolvers);
        exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
        exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
        return exceptionHandler;
    }
    

    完整代码示例

    package tech.xproject.gateway.config;
    
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.boot.autoconfigure.web.ResourceProperties;
    import org.springframework.boot.autoconfigure.web.ServerProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.boot.web.reactive.error.ErrorAttributes;
    import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.codec.ServerCodecConfigurer;
    import org.springframework.web.reactive.result.view.ViewResolver;
    import tech.xproject.gateway.handler.JsonExceptionHandler;
    
    import java.util.Collections;
    import java.util.List;
    
    /**
     * @author kent
     */
    @Configuration
    @EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
    public class ErrorHandlerConfiguration {
    
        private final ServerProperties serverProperties;
        private final ApplicationContext applicationContext;
        private final ResourceProperties resourceProperties;
        private final List<ViewResolver> viewResolvers;
        private final ServerCodecConfigurer serverCodecConfigurer;
    
        public ErrorHandlerConfiguration(ServerProperties serverProperties, ResourceProperties resourceProperties,
                                         ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer,
                                         ApplicationContext applicationContext) {
            this.serverProperties = serverProperties;
            this.applicationContext = applicationContext;
            this.resourceProperties = resourceProperties;
            this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
            this.serverCodecConfigurer = serverCodecConfigurer;
        }
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
            JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes,
                    this.resourceProperties, this.serverProperties.getError(), this.applicationContext);
            exceptionHandler.setViewResolvers(this.viewResolvers);
            exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
            exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
            return exceptionHandler;
        }
    }
    

    [gateway]自定义JsonExceptionHandler

    代码位置:gateway

    使用自定义的结构体返回,code、message、data

    /**
     * get error attributes
     */
    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
        Throwable error = super.getError(request);
        String exMessage = error != null ? error.getMessage() : ResultCodeEnum.ERROR.getMessage();
        String message = String.format("request error [%s %s],exception:%s", request.methodName(), request.uri(), exMessage);
    
        Map<String, Object> map = new HashMap<>(3);
        map.put("code", ResultCodeEnum.ERROR.getCode());
        map.put("message", message);
        map.put("data", null);
        return map;
    }
    

    重写getHttpStatus方法,返回http状态码200

    /**
     * response http code 200
     * the error code need use the code in response content
     *
     * @param errorAttributes
     */
    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {
        return HttpStatus.OK.value();
    }
    

    完整代码示例

    package tech.xproject.gateway.handler;
    
    import org.springframework.boot.autoconfigure.web.ErrorProperties;
    import org.springframework.boot.autoconfigure.web.ResourceProperties;
    import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
    import org.springframework.boot.web.reactive.error.ErrorAttributes;
    import org.springframework.context.ApplicationContext;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.reactive.function.server.*;
    import tech.xproject.common.core.enums.ResultCodeEnum;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author kent
     */
    public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {
    
        public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
                                    ErrorProperties errorProperties, ApplicationContext applicationContext) {
            super(errorAttributes, resourceProperties, errorProperties, applicationContext);
        }
    
        /**
         * get error attributes
         */
        @Override
        protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
            Throwable error = super.getError(request);
            String exMessage = error != null ? error.getMessage() : ResultCodeEnum.ERROR.getMessage();
            String message = String.format("request error [%s %s],exception:%s", request.methodName(), request.uri(), exMessage);
    
            Map<String, Object> map = new HashMap<>(3);
            map.put("code", ResultCodeEnum.ERROR.getCode());
            map.put("message", message);
            map.put("data", null);
            return map;
        }
    
        /**
         * render with json
         *
         * @param errorAttributes
         */
        @Override
        protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
            return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
        }
    
        /**
         * response http code 200
         * the error code need use the code in response content
         *
         * @param errorAttributes
         */
        @Override
        protected int getHttpStatus(Map<String, Object> errorAttributes) {
            return HttpStatus.OK.value();
        }
    }
    

    小结

    在网上查阅各类文章,始终没找到解决方案,只有各类的零散的解决方式,最后通过自己翻代码,断点调试,并结合相关的文章终于解决了。
    使用文章跟代码解决方式记录下来,给有需要的人提供参考。

    完整代码Demo

    feign-custom-exception-code-demo

    参考

    展开全文
  • Feign的底层还是依赖了ribbon来获取nacos上注册的服务,但是有些时候需要调用的服务不一定是注册到我们自己nacos上的微服务

    Feign的底层还是依赖了ribbon来获取nacos上注册的服务,但是有些时候需要调用的服务不一定是注册到我们自己nacos上的微服务,这个时候就要脱离ribbon来自定义请求的url

    自定义demo,比如请求百度

    package com.fchen.usercenter.feignclient;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @FeignClient(name = "abc", url = "http://www.baidu.com")
    public interface SelfFeignClient {
    
        @GetMapping("")
        public String testSelfFeign();
    
    }
    

    Feign服务降级fallback

    feign还有一个强大的功能就是在调用服务失败的时候可以进入自定义回调方法,并且将回调方法的return值返回给调用方.默认是在服务方返回的responsestatus不为200时就进入回调方法

    Spring Cloud Feign HTTP请求异常Fallback容错机制,它是基于Hystrix实现的,所以要通过配置参数feign.hystrix.enabled=true开启该功能.

    在这里插入图片描述

    在这里插入图片描述

    展开全文
  • Feign 客户端捕获不到服务端抛出的异常 解决: 微服务之间接口互相调用,Feign客户端需要捕获服务的抛出的异常,并且返回统一错误格式。 @Configuration public class FeignErrorDecoder implements ...
  • 本文来自读者投稿,原作者——上帝爱吃苹果,人在魔都,目前为贝壳做事,本篇文章主要分享下 Feign 自定义配置的工程实践,希望你们可以找到些有用的东西基于 spring-boot-sta...
  • /** * @author 小石潭记 * @date 2020/6/23 20:53 * @Description: 自定义feign错误异常处理 */ @Configuration public class MyErrorDecoder implements ErrorDecoder { @Override public Exception decode(String...
  • Feign 的编码器、解码器和客户端都是支持自定义扩展,可以对请求以及结果和发起请求的过程进行自定义实现,Feign 默认支持 JSON 格式的编码器和解码器,如果希望支持其他的或者自定义格式就需要编写自己的编码器和...
  • Feign自定义配置

    万次阅读 2017-07-20 10:41:34
    (2)在feignClient类中修改@FeignClient注解,在注解中添加新定义的Feign配置configuration的值: 注意:服务提供者的接口参数必须写在请求路径中,否则请求无效。 不使用自定义的feignClint配置: (3)在...
  • 最近项目中在大量使用Feign和OkHttp作为http客户端使用,开发效率得到显著的提升。但也面临一些问题,比如每个下游系统的异常返回方式不同,需要编写大量的错误处理代码来适应不同的服务,而且错误处理代码混在业务...
  • 关于FeignFallback处理

    千次阅读 2018-07-20 09:35:00
    Feign的不恰当的fallback Feign的坑不少,特别与Hystrix集成之后。 在微服务引入Feign后,上线不久后便发现,对于一个简单的查询类调用,在下游返回正常的"404-资源不存在"这种业务异常时,Feign也做了fallback,...
  • Feign Client 捕获自定义异常

    万次阅读 2019-05-22 12:28:44
    feign.hystrix.enable=false情况下,微服务提供方跑出自定义异常,微服务调用方怎么捕获这个自定义异常? 分两种情况: 1.如果微服务提供了接口声明,微服务调用工程引用了这个接口声明jar,有异常可以正常...
  • feignfallback处理

    千次阅读 2019-12-11 00:07:13
    feign.hystrix.enabled=true开启该功能 什么情况下会进入fallback? 服务方返回的response的status不为200 正常情况下当被调用服务返回response的status不等于200,就会进入到feign.codec.ErrorDecoder#decode方法...
  • Feign--Fallback

    2020-07-26 21:36:10
    其他网址 SpringCloud(三):Feign-单独使用及对hystrix的支持配置 - 掘金
  • 一、在Fegion的Hystrix支持中,我们通过在@FeignClient(fallback = HystrixClientFallback.class),当服务提供者出现异常的时候,使用Hystrix回调方法。但是我们却无法看到具体的异常是什么。那么怎么解决这个问题呢...
  • 首先先创建一个FeignConfig类,代码如下: package com.xing.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org....
  • 第一章文章中,我们在FallBack异常处理中,使用了"FeignException"去自定义异常但是!突然发现会被我们的 sentinel 熔断机制将我们抛出的异常拦截。 解决办法: 1、feign中引入我们自定义异常配置 2、异常...
  • 在FeignClient中,我们通过制定fallback,可以在服务不可用时自动调用fallback制定的处理...下面以microservice-springcloud-movie-feign-with-hystrix模块来说明。 1.定义一个实现FallbackFactory的类 @Component ...
  • 探究清楚 feign 的原理,自定义 feign 功能 spring-cloud-openfeign-core-2.1.1.RELEASE.jar 中 HystrixFeign 的详细构建过程: @EnableFeignClients -> FeignClientsRegistrar 扫描 @Feign注解的类 -> ...
  • Spring Cloud Feign(第四篇)之Fallback

    万次阅读 多人点赞 2018-08-26 11:48:53
    介绍Fallback两种使用方式,实现Feign接口和实现FallbackFactory工厂接口
  • Feign的构建过程及自定义扩展功能

    千次阅读 2019-05-24 20:25:54
    准备工作(配置)2.EnableFeignClients与FeignClientsRegistrar类3.FeignClientFactoryBean4.Targeter4.1.HystrixTargeter4.2.DefaultTargeter5.FeignBuilder5.1.HystrixFeign5.2示例6.总结7.参考资料 spring-cloud...
  • SpringCloud+Feign+Hystrix统一FallbackFactory降级处理

    千次阅读 热门讨论 2021-01-20 18:01:12
    SpringCloud+Feign+Hystrix统一FallbackFactory降级处理概述说明前提源码分析扩展、统一FallbackFactory其他说明结果 概述说明 当我们使用Spring cloud的时候,基本都是会用到Feign、Hystrix相关技术。每一个接口类...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,355
精华内容 1,342
关键字:

fallbackfeign自定义