2012-11-09 90 views
9

我正在編寫一個小型node.js應用程序,它從HTML表單接收多部分POST,並將傳入數據傳輸到Amazon S3。 formidable模塊提供了multipart parsing,將每個部分暴露爲節點Streamknox模塊將PUT處理爲s3。從node.js報告上傳進度

var form = new formidable.IncomingForm() 
, s3 = knox.createClient(conf); 

form.onPart = function(part) { 
    var put = s3.putStream(part, filename, headers, handleResponse); 
    put.on('progress', handleProgress); 
}; 

form.parse(req); 

我通過socket.io報告上傳進度瀏覽器客戶端,但我有困難得到這些數字反映了節點S3上傳的實際進展。

當瀏覽器到節點上傳幾乎立即發生時,就像節點進程在本地網絡上運行時一樣,進度指示器立即達到100%。如果文件很大,即300MB,則進度指示器緩慢上升,但仍然比我們的上游帶寬更快。達到100%的進度後,客戶端掛起,大概等待s3上傳完成。

我知道putStream在內部使用Node的stream.pipe方法,但我不明白這是如何工作的細節。我的假設是,節點儘可能快地吞噬傳入的數據,並將其放入內存中。如果寫入流可以足夠快地獲取數據,那麼很少的數據會一次存儲在內存中,因爲它可以被寫入並丟棄。如果寫入數據流儘管速度很慢,但我們可能必須將所有傳入的數據保存在內存中直到可以寫入。由於我們正在偵聽讀取流上的data事件以發佈進度,因此我們最終報告上傳速度比實際速度快。

我對這個問題的理解是否接近標記?我該如何解決它?我是否需要用write,drainpause來弄髒和骯髒?

+0

你的進展報告返回給瀏覽器的'handleProgress'回調裏面?您尚未發佈可能與實際進度報告有關的_any_代碼。發佈更多的代碼可能會有所幫助。 – lanzz

+0

你正在使用什麼版本的Node.JS?使用'request.pause()'(在你的情況下爲''part'變量)顯示[有一個錯誤](https://groups.google.com/forum/?fromgroups=#!topic/nodejs/pzhtOO6ePZ0) Node.JS v0.6.x,由'.pipe()'在內部使用。這應該在v0.7 +中修復。 – freakish

+0

@lanzz - 是的。但實際的實現並不是真正的相關:爲了這個問題的目的,它可能是''console.log''。 – cantlin

回答

7

你的問題是,stream.pause isn't implemented on the part,這是一個非常簡單的多部分窗體解析器的輸出readstream。

Knox instructs the s3 request to emit "progress" events whenever the part emits "data"。但是,由於part流忽略了暫停,所以進度事件的發出速度與表單數據上傳和解析一樣快。

但是,強大的form確實知道如何同時處理pauseresume(它代理對它正在解析的請求的調用)。

像這樣的東西應該解決您的問題:

form.onPart = function(part) { 

    // once pause is implemented, the part will be able to throttle the speed 
    // of the incoming request 
    part.pause = function() { 
     form.pause(); 
    }; 

    // resume is the counterpart to pause, and will fire after the `put` emits 
    // "drain", letting us know that it's ok to start emitting "data" again 
    part.resume = function() { 
     form.resume(); 
    }; 

    var put = s3.putStream(part, filename, headers, handleResponse); 
    put.on('progress', handleProgress); 
}; 
+0

謝謝@ numbers1311407,很好的答案。我一定會問:你能看出以這種方式實施''暫停'和''恢復'的重大缺陷嗎?實際上,我認爲這使得我們的服務器最多隻能像s3那樣響應。我已經在測試代碼[這裏](https://github.com/cantlin/node-s3-proxy)中實現了它。 – cantlin

+0

因爲我不是I/O高手,我傾向於想知道同樣的事情。但[node.js流文檔頁面](http://nodejs.org/api/http.html#http_request_pause)確實提到了上傳限制作爲「暫停」的有用案例。 [這個關於request.pause「bug」]的新聞組討論(https://groups.google.com/forum/#!msg/nodejs/yv6Dl-O-wYk/qPAKqKDDT9gJ)值得一讀(Mikeal和Marco的評論)。 – numbers1311407

+0

最後,它爲您解決了兩個問題:1)它保持客戶端在線,直到實際上傳完成; 2)它允許在沒有緩衝服務器上潛在的大量數據的情況下發生。您也可以通過在s3請求前管道緩衝流來解決此問題,監視進度,並在上傳完成時回撥客戶端。但是這會拋出#2。 – numbers1311407