如何上傳檔案 (HTML)
[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]
這個主題將說明如何將資料或檔案從裝置上傳到網際網路。
應用程式可以使用本主題討論的 API,讓這些應用程式能夠與 Web 服務互動,以使用或分享普遍使用的媒體格式,如相片、音樂及影片。
對於大量、資料流方式或多部分傳輸 (視訊、音樂以及大型影像),其操作週期可能跨越多個應用程式暫停和 (或) 網路可用性變更,您的應用程式可以使用 Background Transfer。
如需背景傳輸的高階資訊,請參閱在背景傳輸資料。
先決條件
如需建立 JavaScript Windows 市集應用程式的一般協助,請參閱使用 JavaScript 建立您的第一個 Windows 執行階段應用程式。另外,這個主題中使用 JavaScript Promise 來完成非同步操作。如需這種程式設計模式的詳細資訊,請參閱使用 Promise 在 JavaScript 的非同步程式設計。
若要確保應用程式的網路可正常運作,您必須在專案 Package.appxmanifest 檔案中設定功能。 如需每個網路功能的定義,請參閱如何設定網路隔離功能。
下列背景傳輸範例使用 JavaScript,並且使用背景傳輸範例做為依據。
背景傳輸上傳作業
使用背景傳輸時,上傳以 UploadOperation 的方式存在,可公開用於重新啟動或取消作業的一些控制方法。 系統會對每個 UploadOperation 自動處理應用程式事件 (例如暫停或終止) 和連線變更;在應用程式暫停期間上傳仍將繼續,或在應用程式終止之後會暫停或持續下去。此外,設定 CostPolicy 屬性將指出您的應用程式是否開始上傳,而且網際網路連線會使用計量付費網路。
以下的範例會逐步引導您建立和初始化基本上傳,以及如何列舉和重新引入之前應用程式工作階段中的持續作業。
上傳檔案
上傳的建立從 BackgroundUploader 開始。這個類別用來提供讓您的應用程式先設定上傳,再建立結果 UploadOperation 的方法。下列範例示範如何使用必要的 Uri 和 StorageFile 物件來執行這項操作。
識別上傳的檔案和目的地
在開始建立 UploadOperation 之前,我們必須識別要上傳的目標位置 URI,以及要上傳的檔案。在下列範例中,填入 uriString 值的方式是使用 UI 輸入中的字串,而填入 file 值的方式則是使用 PickSingleFileAsync 操作傳回的 StorageFile 物件。
function uploadFile() { var filePicker = new Windows.Storage.Pickers.FileOpenPicker(); filePicker.fileTypeFilter.replaceAll(["*"]); filePicker.pickSingleFileAsync().then(function (file) { if (!file) { printLog("No file selected"); return; } var upload = new UploadOp(); var uriString = document.getElementById("serverAddressField").value; upload.start(uriString, file); // Store the upload operation in the uploadOps array. uploadOperations.push(upload); }); }
建立和初始化上傳作業
在上一個步驟中,uriString 和 file 值已傳遞至我們下一個範例 UploadOp 的執行個體,這兩個值將被用來設定和啟動新的上傳操作。首先,會剖析 uriString 以建立必要的 Uri 物件。
接下來,BackgroundUploader 會使用所提供之 StorageFile (file) 的屬性來填入要求標頭,並以 StorageFile 物件來設定 SourceFile 屬性。接著會呼叫 SetRequestHeader 方法,插入以字串方式提供的檔案名稱和 StorageFile.Name 屬性。
最後,BackgroundUploader 會建立 UploadOperation (upload)。
function UploadOp() { var upload = null; var promise = null; this.start = function (uriString, file) { try { var uri = new Windows.Foundation.Uri(uriString); var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader(); // Set a header, so the server can save the file (this is specific to the sample server). uploader.setRequestHeader("Filename", file.name); // Create a new upload operation. upload = uploader.createUpload(uri, file); // Start the upload and persist the promise to be able to cancel the upload. promise = upload.startAsync().then(complete, error, progress); } catch (err) { displayError(err); } }; // On application activation, reassign callbacks for a upload // operation persisted from previous application state. this.load = function (loadedUpload) { try { upload = loadedUpload; promise = upload.attachAsync().then(complete, error, progress); } catch (err) { displayError(err); } }; }
請注意,非同步方法呼叫是使用 JavaScript Promise 定義的。看看上個範例的行:
promise = upload.startAsync().then(complete, error, progress);
非同步呼叫後面跟著一個指示方法的 then 陳述式,由應用程式定義,會在非同步方法呼叫傳回結果時呼叫它。如需這種程式設計模式的詳細資訊,請參閱使用 Promise 在 JavaScript 的非同步程式設計。
上傳多個檔案
識別上傳的檔案和目的地
在使用一個 UploadOperation 傳輸多個檔案的案例中,程序會照一般的方法開始,也就是先提供必要的目的地 URI 和本機檔案資訊。就像上一節的範例,使用者以字串提供 URI,而 FileOpenPicker 可以用來透過使用者介面指出檔案。不過,在這個案例中,應用程式應該改為呼叫 PickMultipleFilesAsync 方法,啟用透過 UI 選取多個檔案的功能。
function uploadFiles() { var filePicker = new Windows.Storage.Pickers.FileOpenPicker(); filePicker.fileTypeFilter.replaceAll(["*"]); filePicker.pickMultipleFilesAsync().then(function (files) { if (files === 0) { printLog("No file selected"); return; } var upload = new UploadOperation(); var uriString = document.getElementById("serverAddressField").value; upload.startMultipart(uriString, files); // Persist the upload operation in the global array. uploadOperations.push(upload); }); }
針對提供的參數建立物件
接下來的兩個範例使用單一範例方法 startMultipart 中的程式碼,並在上個步驟結束時呼叫它。為了清楚說明,已將建立 BackgroundTransferContentPart 物件陣列方法中的程式碼與建立結果 UploadOperation 的程式碼分開。
首先,使用者提供的 URI 字串被初始化為 Uri。接下來,傳送給這個方法的 IStorageFile 物件陣列 (files) 會不斷重複,並使用每個物件來建立新的 BackgroundTransferContentPart 物件,然後放置在 contentParts 陣列中。
upload.startMultipart = function (uriString, files) { try { var uri = new Windows.Foundation.Uri(uriString); var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader(); var contentParts = []; files.forEach(function (file, index) { var part = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart("File" + index, file.name); part.setFile(file); contentParts.push(part); });
建立和初始化多部分上傳作業
使用我們的 contentParts 陣列 (其中已填入代表每個要上傳的 IStorageFile 的所有 BackgroundTransferContentPart 物件),我們已準備好使用 Uri 來呼叫 CreateUploadAsync,以指示傳送要求的目的地。
// Create a new upload operation. uploader.createUploadAsync(uri, contentParts).then(function (uploadOperation) { // Start the upload and persist the promise to be able to cancel the upload. upload = uploadOperation; promise = uploadOperation.startAsync().then(complete, error, progress); }); } catch (err) { displayError(err); } };
在啟動時列舉持續作業
在 UploadOperation 完成或取消時,會釋放任何關聯的系統資源。不過,如果您的應用程式在這兩件事發生之前終止,就會暫停任何進行中的作業,而且仍會佔用與每個作業關聯的資源。如果這些操作沒有列舉且重新引回下一個應用程式工作階段,這些操作將不會完成,而且仍然會繼續佔用裝置資源。
在定義列舉持續作業的功能之前,我們必須建立一個陣列來包含其將傳回的 UploadOperation 物件:
var uploadOperations = [];
接著我們要定義列舉持續作業的功能,然後將這些作業儲存在我們的陣列。 請注意,將回呼重新指派到 UploadOperation 時所呼叫的 load 方法 (應在應用程式終止期間都持續著),位於我們稍後在本節所定義的 UploadOp 類別中。
function Windows.Networking.BackgroundTransfer.BackgroundUploader.getCurrentUploadsAsync() { .then(function (uploads) { for (var i = 0; i < uploads.size; i++) { var upload = new UploadOp(); upload.load(uploads[i]); uploadOperations.push(upload); } } };
注意
在 Windows Phone 市集應用程式中,當您的應用程式不在前景時,背景傳輸會持續進行。因為在此狀況下您的應用程式並未執行,所以傳輸完成時不會收到通知。當您的應用程式繼續時,如果您只檢查已完成傳輸的進度,狀態會是 BackgroundTransferStatus.Running。不過,當您連接到上述範例程式碼的傳輸時,會引發工作完成處理常式,也會更新傳輸狀態。
要求逾時
要考量的主要連線逾時情況有兩種:
建立要傳輸的新連線時,如果在五分鐘內未建立連線要求,將會中止該要求。
建立連線之後,將中止任何在兩分鐘內未收到回應的 HTTP 要求訊息。
注意 在任一種情況下,假設有網際網路連線,背景傳輸最多會自動重試要求三次。在偵測不到網際網路連線的事件中,其他要求將等到偵測到連線為止。
偵錯指導方針
在 Microsoft Visual Studio 中停止偵錯工作階段就等同於關閉應用程式;PUT 上傳會被暫停,POST 上傳會被終止。即使在偵錯時,應用程式應該列舉然後重新啟動或取消任何之前仍然存在的下載。例如,如果偵錯工作階段與之前的操作無關,您可以在應用程式啟動時,讓應用程式取消已列舉的持續上傳作業。
偵錯工作階段期間在應用程式啟動時列舉下載/上傳,如果該偵錯工作階段與之前的作業無關,您可以讓應用程式取消它們。請注意,如果有 Visual Studio 專案更新,像是變更應用程式資訊清單,而應用程式已解除安裝並重新部署,則 GetCurrentUploadsAsync 無法列舉使用前一個應用程式部署建立的作業。
如需詳細資訊,請參閱偵錯和測試 Windows 市集應用程式。
開發期間使用背景傳送時,您可能會面臨使用中及已完成傳送作業的內部快取不同步的情況。這會導致無法開始新的傳送作業或無法與現有的作業和 BackgroundTransferGroup 物件互動。在某些情況下,嘗試與現有作業互動會造成當機。如果 TransferBehavior 屬性設為 Parallel,就會發生這種結果。這個問題只在開發期間的特定情況下發生,不適用於您應用程式的一般使用者。
使用 Visual Studio 時有四種情況會導致這個問題。
- 您使用與現有專案相同的名稱但不同的語言 (例如,從 C++ 變更為 C#) 建立新的專案。
- 您變更現有專案中的目標架構 (例如,從 x86 變更為 x64)。
- 您變更現有專案中的文化特性 (例如,從中性變更為 en-US)。
- 您在現有專案的套件資訊清單中新增或移除功能 (例如,新增 [企業驗證])。
一般應用程式服務,包括新增或移除功能的資訊清單更新,並不會在應用程式的一般使用者部署上引起這個問題。
若要解決這個問題,請完整解除安裝應用程式的所有版本,然後使用新的語言、架構、文化特性或功能來重新部署。這個操作可以透過 [開始]**** 畫面或使用 PowerShell 和 Remove-AppxPackage Cmdlet 來完成。
摘要與後續步驟
在這個主題中,我們檢閱如何以 JavaScript 使用 Background Transfer API 來上傳檔案。
您也可以在 Windows 市集應用程式下載檔案。如需核心概念與範例說明,請參閱如何下載檔案。
相關主題
其他
使用 Promise 在 JavaScript 的非同步程式設計
使用 JavaScript 建立您的第一個 Windows 執行階段應用程式
參考
Windows.Networking.BackgroundTransfer
範例