5

当我尝试实现ErrorDecoder对 feign 异常进行解码时,我发现输入的流response.body()已关闭,因此当我尝试读取流并转换为字符串时,它会抛出java.io.IOException: stream is closed. 这真的很困惑,因为在解码器之前,我没有做任何事情来关闭高级流。

public class FeignClientErrorDecoder implements ErrorDecoder {
    @Override
    public Exception decode(String methodKey, Response response) {
        log.info("feign client response: {}", response);
        String body = null;
        try {
            body = Util.toString(response.body().asReader(Charset.defaultCharset()));
        } catch (IOException e) {
            log.error("feign.IOException", e);
        }
        return new ServiceException(MessageCode.builder(ExceptionCodeEnum.ERROR));
    }
}
4

2 回答 2

14

我经历了这场噩梦,这都是 IDE 的错。

调试模式下的断点在response.body().asReader导致流关闭之前/结束。

阅读正文后简单地开始调试,一切顺利。

于 2020-06-04T18:02:26.010 回答
3

Logger / System.out.println / IDE 调试模式

在获得之前不要使用上述任何功能response.body()

如果您使用上述任何功能来打印/记录/查看您的response对象,那么它将在response.body()内部处理并关闭InputStream. 所以在这种情况下你会得到Stream is closed错误。

要解决此问题,请response.body()在记录器之前处理。现在您可以通过运行您的应用程序而不是在调试模式下来检查这一点。

示例代码:

@Override
  public Exception decode(final String methodKey, final Response response) {
    final String error = getResponseBodyAsString(response.body());
    LOGGER.error("{} failed with response {}", methodKey, response);
    return new ServiceException("Request failed with status: " + response.status()
                                                         + " and error: " + error);
  }

  private String getResponseBodyAsString(final Response.Body body) {
    try {
      return IOUtils.toString(body.asReader(StandardCharsets.UTF_8));
    } catch (final IOException e) {
      LOGGER.error("Failed to read the response body with error: ", e);
    }
    return null;
  }

注意:如果您处于调试模式,那么您的 IDEA 将处理此响应,因此即使在这种情况下您也会收到相同的错误。所以请不要在调试模式下检查这个。

于 2020-09-22T11:31:06.957 回答