如何使用 FeignErrorDecoder 摆脱 stream is closed 错误?

How to get rid of stream is closed error with FeignErrorDecoder?

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

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 个测试错误。

感谢您提供完整代码。由于在错误解码器中记录 response 而发生错误:

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

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

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

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