2013-04-30 57 views
0

我有一個上傳組件到我的應用程序,它成功地在iFrame中使用舊的表單上傳方法。我有一個Ajax輪詢,每1000ms返回一次上傳進度。xhr2文件上傳 - 使用formData訪問文件名

我正在做功能檢測,並允許有能力的瀏覽器通過xhr2上傳。理論是,我可以在客戶端獲得進展;無需輪詢,進度條更新更加流暢和優雅!在批量上傳結束時,我需要重定向到顯示上傳的所有文件列表的頁面。

你可以通過xhr2上傳兩個文件:每個文件都是自己上傳的,或者你製作一個包含所有文件的「formData」對象。每個人都有好處和缺點,我想我正在努力獲得兩全其美的好處,這可能是不可能的。在「兩全其美」我會滿足這些要求:

  1. 能夠顯示進度和單個文件的文件名,因爲他們去
  2. 能夠作爲包是顯示一個「總進度」欄發送
  3. 捕獲服務器端文件的「包」,並在整個包完成時發回重定向。

下面是單個文件傳輸的示例代碼。我可以輕鬆滿足標準#1,並且可以通過一些努力爲標準#2編寫代碼。 #3有點問題,因爲客戶端只是發送一堆單獨的文件作爲單獨的傳輸。

function uploadFile(file) { 
     xhr = new XMLHttpRequest(); 

     xhr.upload.addEventListener("progress", function(evt) { 
     if (evt.lengthComputable) { 
      //domNode.bar is a cached jQuery object 
      domNode.bar.css('width', (evt.loaded/evt.total) * 100 + "%"); 
      console.log('my current filename is: ' + file.name; 
     } 
     else { 
      // No data to calculate on 
     } 
     }, false); 

     xhr.addEventListener("load", function() { 
     console.log("finished upload"); 
     }, false); 

     xhr.open("post", remoteURL, true); 

     // Set appropriate headers 
     xhr.setRequestHeader("Content-Type", "application/octet-stream"); 
     xhr.setRequestHeader("X-File-Name", file.name); 
     xhr.setRequestHeader("X-File-Size", file.size); 
     xhr.setRequestHeader("X-File-Type", file.type); 


     // Send the file 
     xhr.send(file); 
    } 
} 

以下是用於作爲formData發送的示例代碼。我現在無法滿足標準#1 ...。我能滿足性判據#2,#3相當容易:

function uploadFile(form) { 
     xhr = new XMLHttpRequest(); 

     xhr.upload.addEventListener("progress", function(evt) { 
     if (evt.lengthComputable) { 
      console.log(evt); 
      domNode.bar.css('width', (evt.loaded/evt.total) * 100 + "%"); 
      // no longer have access to the file object 
     } 
     else { 
      // No data to calculate on 
     } 
     }, false); 

     xhr.addEventListener("load", function() { 
     console.log(xhr); 
     }, false); 

     xhr.open("post", remoteURL, true); 

     // Set appropriate headers 
     xhr.setRequestHeader("Content-Type", "multipart/form-data"); 

     // Send the form 
     xhr.send(form); 
    } 
} 

// just assume that I've used formData.append to build a valid form object, 
// which I have; and that this is triggered by a click event or something 
uploadFile(form); 

我不是完全沒有選擇,但在此之前我實現前進我只是想,我不是缺少什麼完整性檢查。以下是我看到的選項:

  1. 繼續僅使用Ajax調用進度。不太流暢,這與我們的設計目標相反,但好處是我不需要使用iFrame進行上傳,因爲我擁有xhr2 API。當流關閉時,我也會得到單個重定向。

  2. 對文件進行迭代,並在客戶端進行一些繁重的工作;除了單個文件進度條之外,我還可以創建一個算法來跟蹤總體進度。同時,我向服務器發送文件計數,並使用此計數延遲重定向URL,直到最後一個文件到達,然後我可以發送它。

有什麼想法?

+0

我不相信你應該在發送FormData時設置內容類型,因爲瀏覽器必須設置邊界名稱。 – idbehold 2013-04-30 18:16:15

+0

謝謝,idbehold。示例代碼我從集合類型中獲取它;但是,它可能會被忽略。無論哪種方式,轉讓的作品。我爲單個文件示例設置了錯誤(應該是application/octet-stream,我相信) – 2013-04-30 18:19:33

+0

您正在爲單個文件示例設置錯誤。另外,在單文件示例中,X-File-Size標頭是不相關的。請求中的Content-Length標題已包含此信息。 – 2013-04-30 18:25:58

回答

1

如果你想發送一個請求中的所有文件,FormData是你唯一的選擇。任一選項都允許您覆蓋點1 & 2.

由於您詢問了其他API,我覺得提到我維護的跨瀏覽器上傳工具是合理的:Fine Uploader。我的圖書館提供回調,可以讓您輕鬆實現目標#1 &#2。就#3而言,Fine Uploader會在單獨的請求中發送每個文件。但是,使用Fine Uploader的API來呈現「全面進度」欄並不困難。我在一個使用Fine Uploader的項目中完成了這項工作。該庫提供了一系列回調函數,並提供了一個綜合的API,在給定了您指定的點的情況下,這些API應該對您有用。

請注意,Fine Uploader中的IE9和更高版本目前不提供上傳進度,但您應該可以使用您的方法通過ajax調用顯示進度。你的方法是一種可能的方法,但是還有另一種可能的選擇,計劃在將來進一步審查:使用Apache/nginx的UploadProgress模塊​​。請參閱功能請求#506

+0

謝謝,雷。我一定會考慮Fine Uploader。您是否可以使用Fine Uploader發送附加信息?我總是可以預先計算出預期的文件數量,然後將文件發送給服務器,然後讓服務器觀看一個計數器,並在預期的編號後發回一些帶有重定向URL和「重定向真實」標誌的回覆的文件已達到...?我發佈的URL將設置一個ID,服務器上有一個具有該ID的對象,因此我可以跟蹤與該特定「會話」相關的所有上傳。 – 2013-04-30 18:44:56

+0

您當然可以通過'params'選項在初始化過程中或上傳初始化後的任何時間(即使在您的一個回調函數中)通過'setParams' API方法發送附加信息。還有一個'complete'回調,它將包含一個參數,其中包含您的服務器在響應中包含的任何數據。您可以根據需要使用這些數據。 API,選項,回調等都完全記錄在案。您最好的選擇是從自述文件的第一頁開始,並根據您的預期用途進行思考。 – 2013-04-30 18:50:22

+0

太棒了,謝謝你的光陰。我會研究Fine Uploader以及其他更一般的建議。如果FU看起來像是我們的答案,那麼我們將不得不進行關於許可的離線討論。 – 2013-04-30 19:01:32