当前位置: 首页 > 知识库问答 >
问题:

如何允许在Hystrix中使用Feign时传播400个错误?

文嘉禧
2023-03-14

我正在构建一个SpringBoot微服务,它调用另一个微服务,当然想使用Hystrix和Feign客户机,这两个客户机都包含在Spring Cloud中。我使用的是camden.sr5版本。

对于任何超时、连接失败和来自Feign的50倍响应代码,我希望Hystrix踢进并正常工作:跳闸断路器和调用回退(如果配置)等。它在默认情况下这样做,所以我很好。

使用以下代码开箱即用:

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.hateoas.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(name = "dog-service", url = "http://...")
public interface DogsFeignClient {
  @RequestMapping(method = RequestMethod.POST, path = "/dogs")
  Resource<Dog> createDog(Dog dog);
}

生成这个异常,它不能很好地将40x响应传递回调用方:

com.netflix.hystrix.exception.HystrixRuntimeException: DogsFeignClient#createDog(Dog) failed and no fallback available.
    at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:805) ~[hystrix-core-1.5.6.jar:1.5.6]
    ....lines ommited for brevity....
Caused by: feign.FeignException: status 400 reading DogsFeignClient#createDog(Dog); content:
{
  "errors" : [ {
    "entity" : "Dog",
    "property" : "numberOfLegs",
    "invalidValue" : "3",
    "message" : "All dogs must have 4 legs"
  } ]
}
    at feign.FeignException.errorStatus(FeignException.java:62) ~[feign-core-9.3.1.jar:na]
    at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:91) ~[feign-core-9.3.1.jar:na]
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-9.3.1.jar:na]
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.3.1.jar:na]
    at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:108) ~[feign-hystrix-9.3.1.jar:na]
    at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:301) ~[hystrix-core-1.5.6.jar:1.5.6]
    at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:297) ~[hystrix-core-1.5.6.jar:1.5.6]
    at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) ~[rxjava-1.1.10.jar:1.1.10]
    ... 26 common frames omitted

当然,我可以查看com.netflix.hystrix.exception.hystrixruntimeExceptioncase字段,其中包含feign.feignException,并且隐藏在描述中的是JSON响应本身,包含换行符等。但是feign.FeignExceptioncase字段是对其本身的引用。是否有一种方法可以传播更深层次的异常而不是HystrixRuntimeException?

还有一种方法可以让下游服务的响应包含原始主体,这样我就不必解构嵌套异常的消息字段了吗?

共有1个答案

陆英毅
2023-03-14

这可以使用单独的配置来实现,该配置将在HystrixBadRequestException的子类中包装400个,并将它们抛给客户端代码。这些例外不影响断路器的状态--如果电路关闭,它将保持关闭,如果它打开,它将保持开放。

@FeignClient(name = "dog-service", 
             url = "http://...", 
             configuration=FeignPropagateBadRequestsConfiguration.class)
public interface DogsFeignClient {
  @RequestMapping(method = RequestMethod.POST, path = "/dogs")
  Resource<Dog> createDog(Dog dog);
}

其中FeignPropagateBadRequestsConfiguration

@Configuration
public class FeignSkipBadRequestsConfiguration {
    @Bean
    public ErrorDecoder errorDecoder() {
        return (methodKey, response) -> {
            int status = response.status();
            if (status == 400) {
                String body = "Bad request";
                try {
                    body = IOUtils.toString(response.body().asReader());
                } catch (Exception ignored) {}
                HttpHeaders httpHeaders = new HttpHeaders();
                response.headers().forEach((k, v) -> httpHeaders.add("feign-" + k, StringUtils.join(v,",")));
                return new FeignBadResponseWrapper(status, httpHeaders, body);
            }
            else {
                return new RuntimeException("Response Code " + status);
            }
        };
    }
}

FeignBadResponseWrapper

@Getter
@Setter
public class FeignBadResponseWrapper extends HystrixBadRequestException {
    private final int status;
    private final HttpHeaders headers;
    private final String body;

    public FeignBadResponseWrapper(int status, HttpHeaders headers, String body) {
        super("Bad request");
        this.status = status;
        this.headers = headers;
        this.body = body;
    }
}

这有点麻烦,您只能在errordecoder中获得响应正文,因为在此之后流将被关闭。但是使用此方法,您可以将响应数据抛出给客户端代码,而不会影响电路:

    try {
        return dogsFeignClient.createDog(dog);
    } catch (HystrixBadRequestException he) {
        if (he instanceof FeignBadResponseWrapper) {
            // obtain data from wrapper and return it to client
        } else {
            // return basic error data for other exceptions
        }
    }
 类似资料:
  • 我正在使用feign创建一个REST客户端。我有我的电话工作,但我想添加一些超时支持,我有一段时间,弄清楚如何做到这一点。 Feign的文档中说:“要将Hystrix与Feign一起使用,请将Hystrix模块添加到类路径中,然后使用HystrixFeign构建器。”好了,现在我有了这个: 现在我的所有方法都在返回HystrixCommands,我可以执行或排队,但仍然看不到如何配置它们。 但是我

  • 问题内容: 此sql代码抛出一个 WHERE中不允许使用聚合函数 如何避免此错误? 问题答案: 用替换子句,如下所示: 与相似,两者均用于过滤结果记录,但用于过滤汇总数据(使用时)。

  • 我在javascript中使用Reactjs和通过AJAX使用API。我们如何解决这个问题?以前我使用CORS工具,但现在我需要启用CORS。

  • 问题内容: 尝试设置密钥时出现“不允许OOM命令”, 通过“ volatile-lru” 设置为500M ,我为发送给redis的每个密钥设置TTL。 命令返回: 如果maxmemory设置为500M,我怎么达到809M? 命令没有显示任何键空间,这怎么可能? 返回“(空列表或集合)”,我试图更改数据库号,但仍未找到键。 这是info命令输出: 问题答案: 您是否有可能更改了数据库数量?如果您使用

  • 从终端创建myDSL语法 起点,包含行列表 每一行都可以选择以LABEL开始,然后以关键字开始 这个语法适用于单引号中有空格的字符串。但是它有很多错误/警告 警告(200):/组织。xtext。实例mydsl/src gen/org/xtext/example/mydsl/parser/antlr/internal/InternalMyDsl。g:309:3:决策可以使用多个选项匹配输入,例如“R

  • 我正试图让spring slueth通过我们的系统提供追踪身份。 在检查其他服务的日志时,我注意到正在生成新的ID。