您的位置 首页 java

使用Rest API传输大文件

如何避免内存不足

介绍

这周,我和我的团队遇到了我在大学时第一次读到的一个问题。 自十月的星期三以来,我完全忘记了它:通过HTTP传输非常大的文件。

需求与设计

我们的客户将其CRM替换为一个云CRM,然后我们将其与整个软件地图集成在一起。

一个集成流程将文档从本地存储发布到CRM,并将其与存储的客户账户关联; 文件大小没有上限,我们假设1 GB为中值。

所有CRM集成均基于 REST ,不允许共享文件夹,暂存数据库,仅允许受保护的REST API OAUTH1。

我在下图中为您绘制了一个简化的建筑模型。

> IMG 1 — Solution Architecture

我们的应用程序与应用程序映射的其他部分一样,在CRM托管在云租户上的前提下在前提环境中运行。

公开的 API 接受包含两部分的Multipart主体:一个包含包含元数据(如文件名,客户帐户ID等)的 json 文档,另一个则包含文件的二进制内容。

标准解决方案

该应用程序由两部分组成:第一部分是文件轮询器,该轮询器每次在临时文件夹中看到一个新文件时都会创建一个线程,而第二部分将其与客户账户相关联并发送给CRM。

如果您有兴趣创建文件轮询器,可以将 apache Camel Polling Consumer链接到您,这是轻松实现的绝佳解决方案。

在此,我有兴趣与您讨论我们将文件发送到CRM的方式。

让我们开始编码; 这是 pom .xml的摘录:

 <dependency>
   <groupId> org .apache.httpcomponents</groupId>      
   <artifactId> httpclient </artifactId>
</dependency>
<dependency>
  <groupId>org.springframework. boot </groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
</dependency>  

这里我们的标准解决方案代码是

 RestTemplate remoteService = new RestTemplate();
//HTTP has two parts:  header  and Body
//Here is the header:
HttpHeader header = new HttpHeader();
//Here is the body
MultiValueMap<String, Object >  bodyMap =  new MultiValueMap<String,Object>();
bodyMap.add(“customer_file”,new FileSystemResource(fileName));
bodyMap.add(“customer_name”, customerJSON);
HttpEntity<MultiValueMap>  request  = new HttpEntity(bodyMap, header);
ResponseEntity<String> restResponse = remoteService . exchange (remoteServiceURL, HttpMethod.POST, request, String);  

customerJson变量是 Java x.json.JsonObject; 这样,多部分请求就可以自主选择正确的内容类型,并且在使用org.springframework.core.io.FileSystemResource实例时,可以期待相同的行为。

我们做了这些测试:

· 发送一个小文件以查找一些格式错误的请求

· 发送一个巨大的文件证明我们的应用程序健壮性

对于本文来说,测试1并没有什么重要的问题,缺少一些标头值,错误的URL格式输入等等。测试2使得我们等待了几分钟,然后所有Java开发人员的噩梦都蒙上了阴影。

出现此问题的原因不仅是因为我们在开发环境中运行了代码,还因为该应用程序试图将整个文件内容加载到内存中,从而使它比J. Wellington Wimpy占用更多的内存。

很清楚,分析应用程序的内存占用量,简单性和简单性。

回顾一下,从架构的角度来看,这也不是一个很好的解决方案,因为:

· 我们无法假设传入文件的最大大小

· 我们无法按顺序处理文件

我们需要改进它。

分块解决方案

我们需要的是修改我们的代码,而不是将整个文件内容加载到内存中,而是使用HTTP1.1支持的功能,直到我上大学的时候:分块传输编码。

此功能告诉服务器传入请求是由多个HTTP消息组成的,它需要接收所有HTTP消息才能开始处理。

从客户端的角度来看,优点在于您仅将当前正在传输的切片加载到内存中。

如果您想进一步了解HTTP如何实现分块传输编码,请遵循WIKI,W3C。

我们改进了正确配置RestTemplate的类:

 RestTemplate remoteService = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false); 
remoteService.setRequestFactory(requestFactory);  

我们重复了测试2,这次运行顺利。

对于1.5 GB文件的完整传输,我们发现内存占用不足300 MB! 成功!

结论

在本文中,我描述了我们发现的传输大型文件的解决方案。 您可以使用不同的库找到多个其他库。

我想补充一点,此功能仅与HTTP1.1一起提供,并且HTTP 2不再支持分块传输编码。 我认为您必须寻找某种流API。

在这里,我们选择使用众所周知的RestTemplate类,而不是较新的WebClient:我无法告诉您是否可以适应它。

最后,我要感谢Luca和Davide在制定完整解决方案上所花费的时间,这些时间启发了本文,当然也感谢我们每天的所有笑声。

(本文翻译自Simone Maletta的文章《Transfer Large Files Using a Rest API》,参考:

文章来源:智云一二三科技

文章标题:使用Rest API传输大文件

文章地址:https://www.zhihuclub.com/188679.shtml

关于作者: 智云科技

热门文章

网站地图