阮曉龍,李朋楠
1(河南中醫藥大學 信息技術學院,鄭州 450046)
2(鄭州祺石信息技術有限公司,鄭州 450008)
大文件上傳是Web 應用系統中常見的問題[1],盡管HTTP 是TCP 上層的協議,但是HTTP 協議本身并不適合處理超大的請求體,文件上傳的穩定性存在著很大的問題.如果傳輸過程中因某種異常而中斷,將前功盡棄,同時,若沒有斷點續傳功能,那文件只能重新上傳,這樣不僅造成帶寬資源的浪費,而且不能保證再次上傳文件就能成功[2].
目前基于HTTP 協議的斷點續傳方案雖然保證大文件上傳過程中的穩定性,但是在傳輸效率和安全性方面仍有不足,滿足不了當前互聯網Web 應用系統的需求,因此基于Web 的大文件高效上傳方法的研究和實現是Web 應用中的重要基礎[3,4].
目前互聯網中,已經存在許多基于Web 上傳文件的方法,文獻[5]中介紹了常用3 種方法如下所示:
(1)HTML Form
該方法主要利用HTML 中Form 表單實現簡單的文件上傳.其中表單的提交方式為POST,編碼類型enctype 為“multipart/form-data”.同時Form 表單里還需要包含一個文件框Input,文件框類型(type)應為file.通過結合Javascript、Ajax 等腳本技術,從而實現文件異步上傳、交互等操作.
(2)RIA 技術
RIA 技術主要是包括Flex、Silverlight、JavaFX等技術,該技術中最常用的文件上傳插件為SWFUpload.
RIA 技術的倡導者為Adobe,其提供了Flex 技術來使程序員可以用編程的方式生成Flash 內容,因此一般常用Flex 技術開發文件上傳的客戶端程序.
同時,與Silverlight、JavaFX 等技術在運行庫方面比較,Flex 也最是輕量級的.
(3)插件技術
在瀏覽器中也可以使用插件實現文件上傳.雖然可能由于客戶瀏覽器的安全性設置,導致插件無法運行,但是在學校內網、企業內網等內部環境還是可以考慮使用的.插件技術主要包括Activex、Applet 等.例如ActiveX 控件,該控件利用Winsock 技術建立與Web 服務之間的通信,并讀取上傳文件數據,再通過Socket 技術把數據以HTTP POST 方式發送給服務器.
此外,文獻[6]中提出了一種文件分塊上傳的方法,使用單線程傳輸,通過固定大小分片可計算得到上傳文件的偏移量,進而較好的實現了大文件的斷點續傳.文獻[2,7]中指出了一種雙線程傳輸方法,即一個線程傳輸文件內容,另一個線程記錄文件內容的偏移量,同樣可實現斷點續傳.這兩種方法雖然可實現斷點續傳,但是其傳輸效率還有待提高.文獻[8]中通過多線程方式,按線程數對文件進行分塊,傳輸效率雖然有所提高,但是其每個線程同樣是通過記錄分塊文件的偏移量,來實現斷點續傳.以上方法均為時序傳輸,一旦中斷再傳,只是從斷點位置繼續上傳,不能保證已上傳文件內容的完整性與正確性.
目前大文件上傳常用方法中主要存在以下4 個方面問題.
(1)單線程上傳
常用的大文件上傳方法一般采用單一線程進行文件的傳輸,對帶寬的利用率較低、穩定性較差,不能較好實現文件傳輸過程中的交互操作.
(2)斷點不續傳
當使用簡單上傳功能來進行大文件上傳,如果上傳的過程中出現了異常造成中斷,那么此次上傳失敗,重試必須從文件起始位置上傳.
(3)安全性不足
常用的大文件上傳方法在文件上傳前后不做完整性和正確性驗證,或只是簡單的進行文件大小方面的完整性驗證,無法保證文件上傳后還是原來的文件.
(4)文件重復上傳
當已成功上傳的文件再次被上傳時,如不能夠有效識別該文件,會使文件再次進行上傳操作,從而造成帶寬、時間資源的浪費.
本文提出基于Web 的大文件高效上傳方法的研究與實現,其中包含7 個關鍵技術,具體如下.
用戶在上傳一個幾百兆、甚至是上千兆的大文件到服務器上時,通常采用的是FTP 協議和某些客戶端軟件,從而能較好地支持大文件的上傳以及實現文件斷點續傳功能.由于HTTP 協議的超大范圍使用和Web 技術的本身特點,也涌現了一批Web 上傳大文件的插件[9,10].
本文提出的方法是基于HTML5 技術可以采用化整為零的文件上傳方法,可將單個大文件轉化為多個小分片文件進行上傳,有效地解決了HTTP 協議本身并不適合處理超大請求文件問題.
在實際工作中,單一的Web 請求往往無法讓網絡傳輸速率達到飽和狀態[8],因此采用多并發的方式進行文件上傳,可以充分利于網絡帶寬、提高文件傳輸速度[7,11].
本文采用構建線程池的方法,使并發線程保持在一個合理值,實現了多并發可控上傳,避免了并發線程過多且無序控制造成的線程排隊長時等待現象,造成資源空耗的浪費.
傳統方式下,文件識別校驗方法主要是對文件傳輸前后的MD5 值進行比對[12,13],該方法在針對小文件時可行,但對大文件或超大文件來說,采用該方法在計算MD5 值時就會非常耗費時間,且有可能造成服務器計算處理失敗而崩潰.
針對此問題,本文提出同樣可采用化整為零的MD5 計算方法,將單個大文件的MD5 計算,轉化為多個小分片文件的MD5 計算,這樣只要確保每個分片的MD5 在上傳前后一致,即可確定在分片有序合并后的文件和原來保持一致[14,15].
斷點續傳是指文件在上傳過程中,如果碰到網絡故障或其他一些因素,導致文件傳輸中斷.待故障恢復后,可以接著未上傳部分繼續上傳,從而節省上傳文件時間[16].
本文斷點續傳不同于其他時序傳輸的斷點續傳,在某一分片首次上傳時,遇到網絡抖動、高延時等短時網絡故障,即使該分片傳輸失敗,傳輸并不會立即中斷,而是會繼續上傳下一個分片,直至網絡恢復或最后一個分片上傳結束.在續傳過程中,并不是簡單的從中斷的文件偏移位置繼續上傳,而會逐個校驗分片的上傳結果,找出傳輸失敗和MD5 不一致的分片進行補充上傳.
極速秒傳是指當服務器上已經存在某個文件,而用戶又要上傳此文件,此時,服務器則會檢測此文件的特征碼已被收錄,就可直接提示用戶文件已上傳完畢,而免去用戶再次上傳的過程[17,18].
要想實現斷點續傳、多并發上傳、文件傳輸校驗等技術,關鍵在于文件分片,而且是在文件上傳前已經完成分片.將大文件進行分片傳輸,可以有效地避免文件上傳過程中可能出現的失敗問題[19,20].
在HTML5 標準制定前,如果實現文件分片,則必須采用某些前端控件來實現;從HTML5 標準制定之后,直接可以使用HTML5 相應的File API 功能函數,解決文件在Web 前端無插件分片的問題.
目前有兩種方法實現對上傳分片文件進行合并,一種是待所有分片傳完之后統一合并,這就需要服務端將接收到的所有分片進行臨時存儲,最終合并也會消耗較長時間;另一種方法是“邊傳邊合并”[19],服務端可以直接將上傳過程中接收到文件分片,按順序追加保存至第一個分片文件中,這就不需要存儲臨時文件,且最終所有分片文件上傳完畢同時也完成文件合并操作,減少文件合并消耗時間.
基于上述大文件上傳方法與關鍵技術,綜合其優缺點,本文提出一種基于Web 的大文件安全高效上傳方案.該方案是基于HTTP 協議,利用HTML5 的XMLHttpRequest 2 特性[21],采用File API 提供的功能函數,實現無客戶端方式下文件分塊傳輸.并在首傳和續傳過程中對每一個分片進行MD5 校驗,提高傳輸安全性.同時利用多線程技術,在前端構建線程池[22],實現多線程的創建與管理,提高文件傳輸的帶寬利用率,進而提升了文件的上傳效率.此外在處理重復文件上傳時,通過提取文件特征碼,匹配已上傳的文件信息庫,如果匹配成功,則可免去重復文件上傳過程,節約帶寬資源及時間成本.其基于Web 的大文件高效上傳方法的邏輯設計過程如圖1 所示.

圖1 并發文件校驗算法流程示意圖
針對文件上傳流程示意圖,基于Javascript 語言對流程中關鍵步驟進行代碼實現,具體如下所示.
在前端分片傳輸過程中,分片大小是一定的,分片越小,請求越多,開銷越大;分片越大,靈活度越小,
分片上傳的優勢就會相對越不明顯[6],因此,分片大小可以根據實際情況設置一個合適的值[23].
本文采取的shardSize = 2×1024×1024.初始化start =currentChunk×shardSize;end = start + shardSize >=file.size? file.size :start + shardSize,變量start 表示的是分片的開始節點,變量end 表示的是分片的終止節點.條件表達式start + shardSize >= file.size? file.size :start +shardSize,功能是獲取下一個分片文件的終止節點.其表達式如式(1)所示.其中x代表分片序號currentChunk,取值從0 開始,遞增量為1;y代表分片大小shardSize,是個固定值;z代表整個文件的大小file.size.

該表達式通過計算起始節點加分片大小獲取文件上傳傳輸的終止結點.參數arrayObj 為所有分片文件的M D 5 碼存放數組,文件的M D 5 碼可以通過spark.end()函數生成.
大文件上傳的前端分片及MD5 計算關鍵代碼摘錄如下所示:


在并發上傳過程中,瀏覽器支持的最大并發數t是一定的,因此設置的并發數如果超過該值,則會造成瀏覽器在執行過程中并發請求排隊等待.所以,并發數的設置越接近t,傳輸效率越大.
本文采取不同并發數來觀察它的效率變化情況,以控制并發數在一個合理值,poolSize 是最大并發請求數,poolCount 是活動并發數.通過定時函數setInterval()來執行并發請求,當poolCount<poolSize 時,就發起一個并發請求進行分片傳輸,poolCount 增加1,傳輸完成后poolCount 減少1,以此來保證并發數在設定值.
多并發上傳的關鍵代碼摘錄如下所示:
var idInt = setInterval(function(){


本次實驗服務器資源配置如表1 所示.

表1 服務器配置信息
為排除其它因素對本次實驗的影響,此次實驗僅保留原生的操作系統,不安裝任何軟件/服務/組件(測試程序除外),最大程度的減少實驗影響因素.
本文提出基于Web 的大文件安全高效上傳方法主要設置參數為瀏覽器請求并發數,為驗證其靈活性及通用性,本次實驗在保持分片大小不變的基礎上,采用不同并發數上傳同一文件進行驗證,重復進行3 次,實現結果如圖2 所示.

圖2 不同線程數文件上傳耗時圖
通過圖2 實驗結果可得出文件傳輸耗時是L 型變化的,請求并發數設置為3 時產生拐點.請求并發數與耗費時間在拐點之前呈反比關系,耗費時間隨著并發數的增大而線性減少,由于網絡帶寬以及瀏覽器軟件等實驗環境因素的影響,在拐點之后耗費時間趨于平穩.
對于文件上傳來說其優劣主要由傳輸的正確性、時間成本、適應性、可移植性、魯棒性這五個方面決定,通過這些判斷條件能夠很好的評估大文件安全高效上傳方案是否準確高效.
本文提出的大文件安全高效上傳方案基于Web方式進行優化,利用HTML5 文件接口對大文件進行前端切片,后端合并,其本質相當于對待上傳文件進行了一次完整的數據傳輸,最終得到結果文件與上傳文件完全相符.在保持文件內容不變的前提下,使用并發上傳能夠大大節約時間成本.其中基于Web 和HTML5 切片的傳輸方式,幾乎能適應所有規模的文件Web 上傳環境;并通過斷點續傳確保了Web 傳輸的可靠性.
本文提出基于Web 的大文件高效上傳方法,在傳統單線程大文件上傳基礎上,采用了多并發上傳,充分利用帶寬資源提高傳輸效率,對于存儲的資源文件進行特征庫收錄,實現已收錄文件的極速秒傳,節約了時間成本.同時對于大文件的MD5 計算,利用循環切片計算的方式極大的降低磁盤I/O 和內存的占用.該方法普適性強、能夠很好地在文件傳輸過程中提高上傳效率、提升穩定性、增強安全性,從而更好地為用戶服務.