【问题标题】:How to get rid of stream is closed error with FeignErrorDecoder?如何使用 FeignErrorDecoder 摆脱流关闭错误?
【发布时间】:2020-07-16 07:21:53
【问题描述】:

我有一个这样构建的假客户端服务:

Feign.Builder builder = Feign.builder()
        .contract(new SpringMvcContract())
        .encoder(new JacksonEncoder())
        .decoder(new JacksonDecoder())
        .errorDecoder(new FeignClientErrorHandler())
return builder.target(targetClass, url);

我有FeignClientErrorDecoder,看起来像这样:

public class FeignClientErrorDecoder implements ErrorDecoder {

    private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new JavaTimeModule());

    @Override
    public Exception decode(final String methodKey,
                            final Response response) {
        try {
            byte[] body = Util.toByteArray(response.body().asInputStream());
            ApiError apiError = MAPPER.readValue(body, ApiError.class);
            return ExceptionFactory.createFrom(apiError);
        } catch (IOException | ApiErrorException e) {
            return new TechnicalClientException("Could not extract error payload.", e);
        }
    }

}

无论我选择哪种读取输入流解决方案,我总是收到stream is closed 错误。 我错过了什么?谁在关闭它?任何解决方法?

完整代码在这里: https://github.com/louisamoros/feign-error-code 您可以运行mvn clean install 并查看 1 个测试有误。

【问题讨论】:

标签: spring-cloud-feign feign


【解决方案1】:

感谢您提供完整的代码。错误是由于在错误解码器中记录了response

LOGGER.error("Feign client error handler. Method: {}, Response: {}", methodKey, response);

这里,toString() 在响应上被调用,包括它的主体。因此,响应体的输入流在此处被读取并关闭,以后无法再次读取。

您可以从日志中删除 response 或复制其输入流(通过 apache IOUtils 或类似的方法),然后使用其副本。在这种情况下,映射器将成功解析所有内容并到达下一行return new ApiException()

顺便说一句,调试这种代码时要小心。现代IDE(例如IntelliJ IDEA)可以在范围内的所有对象上调用toString(),同时默认到达断点,因此同样的问题也可能因此而发生。在这里,您可以安全地将断点放在MAPPER.readValue 行之后。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多