附件的打包下載,需要將一批邏輯上一起的文件,讓用戶通過一個下載按鈕打包下載。首先想到的方案是服務端調用什麼zip
之類的類庫,將文件打包好後返回客戶端。但是這樣做有一個很明顯的問題:文件很多很大的情況下,打包可能會佔用大量的內存和cpu,就算在磁盤上構建臨時的打包文件,也會增加服務器的磁盤IO負擔,而且這些臨時的文件無故佔用大量的磁盤空間,刪除還是個問題。用戶體驗也是問題,因爲必須打包完成後,才能開始返回,無法邊打包邊下載。本來都準備放棄了,不過發現百度網盤好像實現了這個功能,於是再次考慮如何實現。想到我們實際上使用了Nginx作爲文件服務器,會不會有第三方模塊能夠支持這種功能呢?尋覓之後果然有結果,就是本文要探討的mod_zip。
mod_zip介紹
mod_zip
能夠動態的構建zip包,這種動態體現在當Nginx作爲反向代理服務器的時候,該模塊能夠根據上游服務器返回的文件列表來打包文件。mod_zip
實際上是利用Nginx的subreques
t功能,將zip流
發送到客戶端的,而且它實際上只打包不壓縮,所以藉助Nginx本身作爲文件服務器的能力,該模塊的內存佔用十分少,對於上G的大文件也沒有問題。zip文件本身是結構化的,可以自定義目錄結構,所以對於mod_zip
而言,要做的只是添加zip的頭部尾部和zip內部的目錄結構元數據而已,文件數據本身依靠Nginx自身的機制發送。
除此之外,還有如下兩點:
- 由於使用
subrequest
機制,文件甚至可以不在Nginx的服務器本身,可以是上游服務器,甚至是互聯網的遠程服務器上 - 在添加crc校驗後,
mod_zip
還能夠支持HTTP的Range,支持斷點續傳
基本使用
安裝
下載源碼:
重新編譯Nginx,不要make install:
將生成的二進制文件覆蓋現有的二進制文件。通常編譯出來的二進制文件位於源碼目錄的objs/nginx
。更多關於如何添加第三方模塊看如何安裝nginx第三方模塊
使用方法
該模塊不需要在nginx.conf中配置任何東西,一切的行爲取決於上游服務器的響應內容。mod_zip
規定當響應頭中包含X-Archive-Files
的時候,將啓用mod_zip的功能:
同時,響應的body中需要包含一個欲打包的文件的列表,如:
每一行表示一個文件描述,行與行之間有一個換行符(最後也有個換行)。每行從左向右以空格分隔,依次是文件的crc-32校驗,文件大小(Byte),文件的uri,文件名。其中crc-32可以忽略,並用-代替,文件名可以包含目錄,會體現在最後的壓縮包中的目錄結構中。
重點是文件的uri怎麼理解。這裏的/foo.txt
和/bar.txt
並非指向文件系統的路徑,而是一個子請求的地址。比如上面的/foo.txt
實際上會產生一個Nginx自身的請求:http://host/foo.txt
,至於這個請求得到什麼又要根據nginx.conf
中的配置決定了。這樣的設計十分靈活,例如下面的配置:
於是,可以這樣使用文件uri:
這樣兩個文件分別會向遠程服務器請求文件:
上游服務器可以通過在頭部注入Content-Disposition
來控制zip文件的輸出文件名
上游服務器示例
下面是個測試用的上游服務器例子