日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

下載各種文件(文本或二進制文件)是每個企業應用程序的生死攸關的事情。 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

總結

以上是生活随笔為你收集整理的编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。