Spring Boot 微服务之间通过FeignClient进行大文件下载:

 

使用FeignClient作为中间件进行一个微服务之间的调用的时候,一般的服务请求是没有什么问题,但是,当下载大文件,会出现:java heap space

也就是堆溢出问题。

 

具体解决方案如下:

 

1、首先是service层返回ResponseEntity

2、@FeignClient的remote接口返回Response对象(FeignClient提供的Response对象)

3、前端层获取Response对象之后,可以获取headers和body信息.代码如下:

 

Response response = exploreServiceRemote.downPackSensorDataFile(recordCode, uniqueCode);
Map> headers = response.headers();
HttpHeaders httpHeaders = new HttpHeaders();

headers.forEach((key, values) -> {
    List headerValues = new LinkedList<>();
    headerValues.addAll(values);
    httpHeaders.put(key, headerValues);
});

Response.Body body = response.body();
try {
    InputStream inputStream = body.asInputStream();//HttpURLInputStream
    InputStreamResource resource = new InputStreamResource(inputStream);
    return ResponseEntity
        .ok()
        .contentType(MediaType.APPLICATION_OCTET_STREAM)
        .headers(httpHeaders)
        .body(resource);
} catch (IOException e) {
    throw new SdsResourceFileNotFoundException(
        MessageFormat.format("Can not download resource recordCode [{0}] and uniqueCode [{1}]",
            recordCode, uniqueCode));
}

具体跟踪的源码:

Spring Boot 微服务之间通过FeignClient进行大文件下载:_第1张图片

看这个源码可以知道:只要当我们的FeignClient的接口返回的是feign.Response类型的时候,才有可能扔过去response。而且,他还有验证,就是你的body为null,或者你的body的长度大于这个MAX_RESPONSE_BUFFER_SIZE的时候,这个值是8192L,也就是8KB的大小,所以,在这个范围内,不用担心堆溢出问题,如果都不符合,那就直接读取流转成byte数组。

如果:你的FeginClient的注解的接口的方法返回的不是feign.Response类型,那么肯定就是走decode(response)这个方法了,这个方法的源码如下:

@Override
    public Object decode(Response response, Type type) throws IOException {
      if (response.status() == 404) return Util.emptyValueOf(type);
      if (response.body() == null) return null;
      if (byte[].class.equals(type)) {
        return Util.toByteArray(response.body().asInputStream());
      }
      return super.decode(response, type);
    }

看这个方法源码也是读取所有内容到一个byte数组当中去,所以下载大文件的时候,一定要设置返回feign.Response类型 

 

你可能感兴趣的:(spring)