如何上载文件 (HTML)

[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]

本主题向你介绍如何将来自设备的数据或文件上载到 Internet。

应用可以使用本主题中讨论的 API 支持其应用与 Web 服务交互,以使用或共享流行的媒体格式,如照片、音乐和视频。

对于操作生命周期可能跨越多个应用挂起和/或网络功能更改的大型基于流的传输或分段传输(视频、音乐和大型图像),你的应用可以使用 Background Transfer

有关对后台传输的概要介绍,请参阅后台传送数据

先决条件

有关创建 JavaScript Windows 应用商店应用的常规帮助,请参阅创建你的第一个使用 JavaScript 的 Windows 运行时应用。此外,在本主题中使用 JavaScript Promise 来完成异步操作。有关此编程模式的详细信息,请参阅在 JavaScript 中使用 Promise 进行异步编程

为了使你的应用能够使用网络,你必须在项目 Package.appxmanifest 文件中设置此功能。 有关每个网络功能的定义,请参阅如何配置网络隔离功能

以下后台传输示例使用 JavaScript,且基于 后台传输示例

后台传输上载操作

如果使用后台传输,上载作为 UploadOperation 存在,该对象具有一系列用于重启和取消操作的控制方法。 系统根据 UploadOperation 自动处理应用事件(如暂停或终止)和连接更改;在应用挂起期间或暂停时,上载会继续运行,并且在应用终止后,仍然保持运行。此外,正确设置 CostPolicy 可指示在对 Internet 连接使用按流量计费的网络时,应用是否将开始上载。

以下示例将指导你完成基本上载的创建和初始化,以及如何枚举和重新引入以前应用会话中保持的操作。

上载文件

创建上载从 BackgroundUploader 开始。该类用于提供使应用能够在创建结果 UploadOperation 之前配置上载的方法。以下示例说明如何使用所需的 UriStorageFile 对象执行该操作。

  1. 标识文件和目标以用于上载

    我们首先需要识别要上载的目标位置的 URI 和要上载的文件,然后才能开始创建 UploadOperation。在以下示例中,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);
        });
    }
    
  2. 创建和初始化上载操作

    在前一步骤中,uriStringfile 值会传递给下一个示例 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 语句,它指示从异步方法调用返回结果时调用的方法(由应用定义)。有关此编程模式的详细信息,请参阅在 JavaScript 中使用 Promise 进行异步编程

上载多个文件

  1. 标识文件和目标以用于上载

    在涉及到使用单个 UploadOperation 传输多个文件的方案中,这一过程将如通常一般开始,首先提供必要的目标 URI 和本地文件信息。与上一部分中的示例类似,由最终用户以字符串形式提供 URI,并且也可以使用 FileOpenPicker 提供通过用户界面指示文件的功能。但在此方案中,应用应改为调用 PickMultipleFilesAsync 方法,以便能够通过用户界面选择多个文件。

    
    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);
       });
    }
    
  2. 创建给定参数的对象

    下面的两个示例使用单示例方法 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);
            });
    
  3. 创建和初始化分段上载操作

    在使用所有 BackgroundTransferContentPart 对象(表示每个要上载的 IStorageFile)填充 contentParts 数组后,我们将准备使用 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 时,将释放关联的任何系统资源。然而,如果在发生这些操作之前终止应用,将中止任何活动操作,并仍将占有与每个操作相关的资源。如果未枚举这些操作并且未重新引入下一个应用会话,那么它们将不会完成并将继续占有设备资源。

  1. 在定义枚举持续操作的函数之前,我们需要创建包含将返回的 UploadOperation 对象的数组:

    var uploadOperations = [];
    
  2. 接下来,我们要定义函数来枚举持续操作,并将其存储到数组中。 请注意,load 方法用于重新分配 UploadOperation 的回调,对于该方法在应用终止过程中是否应持续,我们将在本节后续部分的 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。但是,当你连接到传输(如上面的示例代码所示)时,将引发任务完成处理程序,并且将更新传输状态。

请求超时

需要考虑两个主要的连接超时方案:

  • 为传输建立新连接时,如果未在 5 分钟内建立连接请求,则会中止连接请求。

  • 建立连接之后,会中止在两分钟内未收到响应的 HTTP 请求消息。

注意  在任何一种方案中,假定存在 Internet 连接,后台传输将最多自动重试一个请求三次。如果未检测到 Internet 连接,则其他请求将一直等待,直到检测到 Internet 连接。

 

调试指南

在 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 应用商店应用中下载文件。有关核心概念和示例说明,请参阅如何下载文件

相关主题

其他

访问连接和流量套餐信息

使用 JavaScript 中的 Promises 进行异步编程

创建你的第一个使用 JavaScript 的 Windows 运行时应用

如何配置网络功能

如何使用 WinJS xhr 下载文件

参考

BackgroundUploader

UploadOperation

Windows.Networking.BackgroundTransfer

示例

后台传输示例

HttpClient 示例

如何下载文件

Windows.Networking.BackgroundTransfer

后台传输示例