1. 程式人生 > >Spring Boot 微服務之間通過FeignClient進行大檔案下載:

Spring Boot 微服務之間通過FeignClient進行大檔案下載:

使用FeignClient作為中介軟體進行一個微服務之間的呼叫的時候,一般的服務請求是沒有什麼問題,但是,當下載大檔案,會出現:java heap space

也就是堆溢位問題。

具體解決方案如下:

1、首先是service層返回ResponseEntity<Resource>

2、@FeignClient的remote介面返回Response物件(FeignClient提供的Response物件)

3、前端層獲取Response物件之後,可以獲取headers和body資訊.程式碼如下:

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

headers.forEach((key, values) -> {
    List<String> 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));
}

具體跟蹤的原始碼:

看這個原始碼可以知道:只要當我們的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型別