下载各种文件(文本或二进制文件)是每个企业应用程序的生死攸关的事情。 PDF文档,附件,媒体,可执行文件,CSV,超大文件等。几乎每个应用程序迟早都必须提供某种形式的下载。 下载是通过HTTP来实现的,因此完全包含此协议并充分利用它很重要。 特别是在面向Internet的应用程序中,诸如缓存或用户体验之类的功能值得考虑。 本系列文章提供了实现各种下载服务器时可能要考虑的各个方面的列表。 请注意,我避免使用“ 最佳实践 ”一词,这些只是我认为有用的准则,但不一定总是适用。

最大的可伸缩性问题之一是在流传输之前将整个文件加载到内存中。 将完整文件加载到byte[]以便稍后从Spring MVC控制器返回它,这是无法预测的,并且无法缩放。 服务器将消耗的内存量与并发连接数乘以平均文件大小成线性关系,而您实际上并不想太依赖这些因素。 将文件内容直接从服务器逐字节流式传输到客户端(使用缓冲)非常容易,实际上有很多技术可以实现。 最简单的一种是手动复制字节:

@RequestMapping(method = GET)
public void download(OutputStream output) throws IOException {try(final InputStream myFile = openFile()) {IOUtils.copy(myFile, output);}
}

您的InputStream甚至不必缓冲, IOUtils.copy()会解决这个问题。 但是,此实现相当底层,并且很难进行单元测试。 相反,我建议返回Resource

@RestController
@RequestMapping("/download")
public class DownloadController {private final FileStorage storage;@Autowiredpublic DownloadController(FileStorage storage) {this.storage = storage;}@RequestMapping(method = GET, value = "/{uuid}")public Resource download(@PathVariable UUID uuid) {return storage.findFile(uuid).map(this::prepareResponse).orElseGet(this::notFound);}private Resource prepareResponse(FilePointer filePointer) {final InputStream inputStream = filePointer.open();return new InputStreamResource(inputStream);}private Resource notFound() {throw new NotFoundException();}
}@ResponseStatus(value= HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {
}

创建了两个抽象以使Spring控制器与文件存储机制脱钩。 FilePointer是一个文件描述符,与该文件的获取位置FilePointer 。 目前,我们使用一种方法:

public interface FilePointer {InputStream open();//more to come}

open()允许读取实际文件,无论它来自何处(文件系统,数据库BLOB,Amazon S3等)。我们将逐步扩展FilePointer以支持更多高级功能,例如文件大小和MIME类型。 查找和创建FilePointer的过程由FileStorage抽象控制:

public interface FileStorage {Optional<FilePointer> findFile(UUID uuid);
}

流式传输使我们能够处理数百个并发请求,而不会显着影响内存和GC( IOUtils仅分配了一个小缓冲区)。 顺便说一句,我正在使用UUID来识别文件,而不是名称或其他形式的序列号。 这使得猜测单个资源名称变得更加困难,因此更加安全(晦涩)。 下一篇文章将对此进行更多介绍。 有了此基本设置,我们可以可靠地为大量并发连接提供服务,而对内存的影响最小。 请记住,Spring框架中的许多组件和其他库(例如servlet过滤器)可能会在返回完整响应之前对其进行缓冲。 因此,进行集成测试以下载巨大的文件(以数十个GiB格式)并确保应用程序不会崩溃非常重要。

编写下载服务器

  • 第一部分:始终流式传输,永远不要完全保留在内存中
  • 第二部分:标头:Last-Modified,ETag和If-None-Match
  • 第三部分:标头:内容长度和范围
  • 第四部分:有效地实现HEAD操作
  • 第五部分:油门下载速度
  • 第六部分:描述您发送的内容(内容类型等)
  • 这些文章中开发的示例应用程序可在GitHub上找到。

翻译自: https://www.javacodegeeks.com/2015/06/writing-a-download-server-part-i-always-stream-never-keep-fully-in-memory.html

编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中相关推荐

  1. grpc 流式传输_编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中...

    grpc 流式传输 下载各种文件(文本或二进制文件)是每个企业应用程序的生死攸关的事情. PDF文档,附件,媒体,可执行文件,CSV,超大文件等.几乎每个应用程序迟早都必须提供某种形式的下载. 下载是 ...

  2. mwc校准油门_编写下载服务器。 第五部分:油门下载速度

    mwc校准油门 在僵尸网络时代,您可以租用几百美元来运行自己的分布式拒绝服务攻击,拥有紧急开关来有选择地关闭昂贵的功能或严重降低性能是一个巨大的胜利. 在缓解问题的同时,您的应用程序仍可运行. 当然, ...

  3. 服务器禁止head 请求_编写下载服务器。 第四部分:有效地执行HEAD操作

    服务器禁止head 请求 HEAD是一个经常被遗忘的HTTP方法(动词),其行为类似于GET,但不返回正文. 您使用HEAD来检查资源的存在(如果不存在,它应该返回404),并确保您的缓存中没有陈旧的 ...

  4. 服务器编写_编写下载服务器。 第六部分:描述您发送的内容(内容类型等)...

    服务器编写 就HTTP而言,客户端下载的只是一堆字节. 但是,客户真的很想知道如何解释这些字节. 它是图像吗? 还是ZIP文件? 本系列的最后一部分描述了如何向客户端提示她下载的内容. 设置 内容类型 ...

  5. 502无法解析服务器标头_编写下载服务器。 第三部分:标头:内容长度和范围...

    502无法解析服务器标头 这次,我们将探索更多HTTP请求和响应标头,以改善下载服务器的实现: Content-length和Range . 前者表示下载量很大,后者允许部分下载文件,或者从我们开始的 ...

  6. 502无法解析服务器标头_编写下载服务器。 第二部分:标头:Last-Modified,ETag和If-None-Match...

    502无法解析服务器标头 客户端缓存是万维网的基础之一. 服务器应通知客户端资源的有效性,客户端应尽可能快地对其进行缓存. 如我们所见,如果不缓存Web,它将非常缓慢. 只需在任何网站上Ctrl + ...

  7. 编写下载服务器。 第五部分:油门下载速度

    在僵尸网络时代,您可以租用几百美元来运行自己的分布式拒绝服务攻击,拥有紧急开关有选择地关闭昂贵的功能或极大地降低性能是一个巨大的胜利. 在缓解问题的同时,您的应用程序仍可运行. 当然,这种安全措施在高 ...

  8. 编写下载服务器。 第四部分:有效地实现HEAD操作

    HEAD是一个经常被遗忘的HTTP方法(动词),其行为类似于GET,但不会返回正文. 您使用HEAD来检查资源的存在(如果不存在,它应该返回404),并确保您的缓存中没有陈旧的版本. 在这种情况下,您 ...

  9. 编写下载服务器。 第二部分:标头:Last-Modified,ETag和If-None-Match

    客户端缓存是万维网的基础之一. 服务器应告知客户端资源的有效性,客户端应尽可能快地对其进行缓存. 如我们所见,如果不缓存Web,将会非常慢. 只需在任何网站上Ctrl + F5并将其与普通F5进行比较 ...

最新文章

  1. iOS 9应用开发教程之ios9的视图
  2. java与c/c++进行socket通信的一些问题(2)
  3. 查看ssh端口号_萌新云服务器折腾记-SSH配置
  4. 隐马尔可夫模型(HMM)及Viterbi算法
  5. CF924D. Contact ATC
  6. QT5_PYQT导入自己的图片
  7. Latex可能遇到的一些问题
  8. VB案例:打印输出图形与文本
  9. iPhone 13拍照马赛克、换屏无法解锁Face ID、iPad mini 6“果冻屏”:等“百香果”吧...
  10. ios系统定义的url
  11. iOS求职之OC面试题完整版---持续更新中...
  12. 补天五星计划范围更新,还有单个漏洞额外10000元现金奖励?!
  13. Android高级开发面试题目,再也不用担心不能升职加薪了。
  14. 基于进程的游戏Server端架构设计
  15. C3P0连接池的配置方式
  16. django memery cache
  17. 神来之笔-线程变量实践
  18. 用 vs 跑 lvgl 模拟器
  19. python 基础 —— sys.path 与 sys.path.append
  20. 娱乐_3D相册(HTML)_七夕

热门文章

  1. 人脸注册源码faceregiste
  2. MySQL中有外键时数据表的删除方法
  3. 怎样批量获取文件名,批量提取文件名 文件名读取windows 批处理文件
  4. 拼图游戏C语言课设实验报告,C语言拼图游戏实验报告.doc
  5. 微型计算机中被处理信息称为,2011海南省计算机等级考试试题 二级C试题考资料...
  6. ping 命令使用代理_网络检测知识篇:ping命令使用知识,你知道几点?
  7. c++ 凸包 分治算法_三维凸包
  8. Docker-Desktop储存路径更改
  9. jdk10与jdk9的区别_JDK 8与JDK 10:三元/拆箱的区别
  10. apache.camel_在即将发布的Camel 2.21版本中改进了使用Apache Camel和ActiveMQ Artemis处理大型消息的功能...