RestTemplate 下载文件
1. 概述
本教程中,我们将展示使用 RestTemplate 下载大文件的不同技术。
2. RestTemplate
RestTemplate 是 Spring 3 中引入的同步阻塞式 HTTP 客户端。根据 Spring 官方文档 介绍,在将来的版本中它可能会被弃用,因为他们已在 Spring 5 中引入了 WebClient 作为非阻塞式 Reactive HTTP 客户端。
3. 陷阱
通常,当我们下载文件时,我们会将其保存在本地文件系统中,或者作为字节流加载到内存中。但是,当遇到大文件时,内存加载可能会造成 OutOfMemoryError。因此,当我们读取 response 块时,必须将其保存到文件中。
我们先来看这两种不起作用的方法:
第一个,当我们将 Resource 作为我们的返回值类型时会发生什么?
Resource download() {
return new ClassPathResource(locationForLargeFile);
}
ResourceHttpMesssageConverter 会将整个 response 块加载到 ByteArrayInputStream 中,依旧增加了我们本想避免的内存压力。
第二个,当我们配置 ResourceHttpMessageConverter#supportsReadStreaming 方法,并返回 InputStreamResource,会发生什么?好吧,它也不会起作用,**当我们调用 InputStreamResource.getInputStream() 时,将得到一个 socket closed 错误!**这是由于 execute 方法在它退出前会关闭 response 输入流所造成的。
所以我们可以怎样解决这个问题呢?实际上,也有两种办法:
基于它们的灵活性和实现难度,本教程对第二种解决方案来展开介绍。
4. 无需恢复的下载
让我们来实现一个 ResponseExtractor,用以将 body 写入到临时文件中。
File file = restTemplate.execute(FILE_URL, HttpMethod.GET, null, clientHttpResponse -> {
File ret = File.createTempFile("download", "tmp");
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
return ret;
});
Assert.assertNotNull(file);
Assertions
.assertThat(file.length())
.isEqualTo(contentLength);
这里我们使用 StreamUtils.copy 将 response 输入流复制到 FileOutputStream 中,同样,也可以使用 其他方式 来实现。
5. 可暂停和恢复的下载
当我们进行大文件下载时,可能会因为某些原因,我们会在暂停之后继续进行下载。
所以,第一步,我们需要检查 URL 下载链接是否支持恢复下载:
HttpHeaders headers = restTemplate.headForHeaders(FILE_URL);
Assertions
.assertThat(headers.get("Accept-Ranges"))
.contains("bytes");
Assertions
.assertThat(headers.getContentLength())
.isGreaterThan(0);
然后,我们可以实现 RequestCallback 来自定义 Range 请求头来恢复下载:
restTemplate.execute(
FILE_URL,
HttpMethod.GET,
clientHttpRequest -> clientHttpRequest.getHeaders().set(
"Range",
String.format("bytes=%d-%d", file.length(), contentLength)),
clientHttpResponse -> {
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(file, true));
return file;
});
Assertions
.assertThat(file.length())
.isLessThanOrEqualTo(contentLength);
如果我们不确定具体的 Content 长度,可以使用如下的 String.format 形式来设置 Range 请求头
String.format("bytes=%d-", file.length())
RestTemplate 下载文件相关推荐
- Java FTP下载文件以及编码问题小结
问题 之前在开发过程中,遇到了一点问题,我要访问一个FTP服务器去下载文件详细情况如下: 1. 需要传入一个可能为中文的文件名: 2. 通过文件名去FTP上寻找该文件: 3. FTP服务器的命名编码为 ...
- java 文件下载方法_【工具类】Java后台上传下载文件的几种方式
/** * 将本地照片上传至腾讯云服务上 */ public void uploadImage(String localImagePath) throws Exception { // 1.将订单照片 ...
- java如何从https下载链接中下载文件
java如何从https下载链接中下载文件 文章目录 java如何从https下载链接中下载文件 从https 下载文件会存在什么用的问题? 导入安全证书到jdk 下载文件 URL 获取inputSt ...
- 【java从网络外链接下载文件并回传到其他网络服务器】
java从网络外链接下载文件并回传到其他网络服务器 场景 描述 举例 解决方案 准备 例子 说明,如果是springboot项目 测试 其他更细粒度实现的文件上传至远程(网络)服务器例子 场景 描述 ...
- 用python下载文件的若干种方法汇总
压缩文件可以直接放到下载器里面下载的 you-get 连接 下载任意文件 重点 用python下载文件的若干种方法汇总 写文章 用python下载文件的若干种方法汇总 zhangqibot发表于Met ...
- 初级版python登录验证,上传下载文件加MD5文件校验
服务器端程序 import socket import json import struct import hashlib import osdef md5_code(usr, pwd):ret = ...
- linux快捷上传下载文件
借助securtCRT,使用linux命令sz可以很方便的将服务器上的文件下载到本地,使用rz命令则是把本地文件上传到服务器 其中,对于sz和rz的理解与记忆我用了如下的方法(因为很多时候容易搞混): ...
- 基于php下载文件的详解
基于php下载文件的详解 本篇文章是对php下载文件进行了详细的分析介绍,需要的朋友参考下 php下载文件,比如txt文件. 出现的效果就是,弹出浏览器自带的下载框,出现另存为操作.有时候会出现内存溢 ...
- java上传加密_Java上传下载文件并实现加密解密
使用 Jersey 服务器实现上传,使用 HTTP 请求实现下载 引入依赖 在 pom.xml 中添加 Jersey 相关依赖 com.sun.jersey jersey-client 1.18.1 ...
- sftp shell 批量上传文件_Shell自动上传下载文件到SFTP服务器
1.说明 本文提供一个Shell脚本, 可以自动连接到SFTP服务器, 然后上传或者下载指定的文件, 进而可以使用Linux的corntab命令, 定时执行脚本上传下载文件, 实现文件的同步或者备份功 ...
最新文章
- centos7挂载windows共享文件夹
- [ERROR]在删除BizTalk主机之前必须删除其所有实例?
- vscode设置键盘快捷键
- java web轻量级开发面试教程内容精粹:哪些简历得不到面试机会
- 学习笔记(38):Python实战编程-窗体显示
- React开发(262):react中活动时间回显用moment
- Python多态、鸭子类型
- 1631. 最小体力消耗路径
- 异常处理--“System.BadImageFormatException”类型的未经处理的异常在 DataTest.exe 中发生
- failed to fetch url linux,ubuntu apt-get下载报failed to fetch错误,请问如何解决
- 十六种CAD.CAE.CAM软件介绍
- 运维分级发布_运维必备制度:故障分级和处罚规范
- Oracle 12c中的MGMTDB
- 2015数据泄露调查报告
- 设备管理器中的usb打印支持有个叹号是什么意思,如何解决?
- js前端double无法显示,long精度丢失,layUI数据表格
- 编程入门先学python好不好,学python用什么软件编程
- 计算机如何连接发票打印机,惠普打印机怎么连接电脑详细步骤,发票打印机怎么添加-...
- 深圳云计算培训:新手学习云计算的规划
- 使用python自动上传apk到蒲公英