RestTemplate:有没有办法保护 jvm 免受巨大响应大小的影响?

RestTemplate: Is there a way to protect jvm agains huge response size?

当使用 RestTemplate 与外部服务对话时,我不止一次在我们的应用程序中看到 OutOfMemory 错误,因为该服务流式传输大量数据(由于他们这边的实施不当,如果出现错误,他们他们在数组的每个元素中发送回大堆栈跟踪,通常包含几千个)。它以大约 6gb 的数据结束,由 jackson 在我们的应用程序中序列化并完全爆炸了 jvm 的 Xmx。

我环顾四周,但似乎没有任何方法可以防止这种情况发生,即当流式响应超过给定大小时中止请求。

有解决办法吗?我们正在使用 apache 的 httpcomponents httpclient 4.5.5,但任何其他底层实现都是可以接受的。

除了 RestTemplates,Spring 的响应式 WebClient 的解决方案也将受到欢迎。

这必须在底层 HTTP 客户端库中强制执行(spring 支持不同的库,例如 JDK 客户端、apache 客户端、okHTTP..)

你在这里谈论 apache-httpcomponent ,你检查过这个 HttpEntity.getContent() 吗? 它实际上 returns 一个 InputStream ,您可以自己阅读并确定何时超过大小..

https://hc.apache.org/httpcomponents-core-4.4.x/httpcore/apidocs/org/apache/http/HttpEntity.html

作为记录,这里是最终解决方案。问题在于使用分页(通过弹性搜索滚动 api)加载可能非常大的对象列表。

ResponseExtractor<Car[]> responseExtractor = responseEntity -> {
    long pageContentLengthInBytes = responseEntity.getHeaders().getContentLength();
    long presumableFreeMemoryInBytes = this.getAvailableFreeMemoryAmount();

    if (presumableFreeMemoryInBytes - TWENTY_MEGABYTES < pageContentLengthInBytes) {
        log.error("Not enough memory to store the page ({} avaiable, content-length={}, trashing it", presumableFreeMemoryInBytes, pageContentLengthInBytes);
        responseEntity.close();
        return null;
    }
    return objectMapper.readValue(responseEntity.getBody(), Car[].class);
};

Car[] responseEntities = this.restTemplate.execute(uri, HttpMethod.GET, null, responseExtractor);
   /**
     * Returns the current amount of memory which may be allocated until an out-of-memory error occurs.
     * see 
     */
    private long getAvailableFreeMemoryAmount() {
        long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
        return Runtime.getRuntime().maxMemory() - allocatedMemory;
    }