【问题标题】:xhr2 file upload - accessing filenames with formDataxhr2 文件上传 - 使用 formData 访问文件名
【发布时间】:2013-04-30 16:52:55
【问题描述】:

我的应用程序有一个上传组件,它成功地使用了 iFrame 中的旧表单上传方法。我有一个 Ajax 投票,每 1000 毫秒返回一次上传进度。

我正在进行功能检测并允许有能力的浏览器通过 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,直到最后一个文件到达,然后我才能发送它。

有什么想法吗?

【问题讨论】:

  • 我不相信您应该在发送 FormData 时设置内容类型,因为浏览器必须设置边界名称。
  • 谢谢,我知道。我从设置内容类型中获取的示例代码;但是,它可能会被覆盖。无论哪种方式,转移工作。我为单个文件示例设置错误(我相信应该是 application/octet-stream)
  • 您在单文件示例中设置错误。此外,在单文件示例中,X-File-Size 标头是无关紧要的。请求中的 Content-Length 标头已包含此信息。
  • 谢谢雷。已经提到我发现它设置错误。不幸的是,选择代码语法并不能帮助我看到我的实际问题!
  • 您的实际问题是什么?您有什么具体问题?

标签: javascript xmlhttprequest


【解决方案1】:

如果您想在一个请求中发送所有文件,FormData 是您唯一的选择。任一选项都允许您涵盖第 1 点和第 2 点。

既然您询问了其他 API,我觉得有必要提及我维护的跨浏览器上传工具:Fine Uploader。我的库提供回调,让您轻松实现目标#1 和#2。就#3 而言,Fine Uploader 在单独的请求中发送每个文件。但是,使用 Fine Uploader 的 API 呈现“总进度”栏并不难。我已经在一个使用 Fine Uploader 的项目中做到了这一点。鉴于您指定的要点,该库提供了一堆回调并公开了一个对您应该有用的综合 API。

请注意,上传进度目前在 IE9 和更早版本的 Fine Uploader 中不可用,但您应该能够使用您的方法通过 ajax 调用显示进度。您的方法是一种可能的方法,但还有另一种可能的选项,计划在未来进一步审查:使用 Apache/nginx 的 UploadProgress 模块。请参阅功能请求#506

【讨论】:

  • 谢谢,雷。我一定会研究 Fine Uploader。您可以使用 Fine Uploader 随请求发送附加信息吗?我总是可以预先计算预期的文件数量,将其与文件一起发送,然后让服务器监视计数器并在预期数量后发送带有重定向 URL 和“redirect true”标志的某种回复的文件已达到...?我发布到的 URL 将设置一个 ID,并且服务器有一个具有该 ID 的对象,因此我可以跟踪与该特定“会话”相关的所有上传。
  • 您当然可以发送其他信息:在初始化期间通过params 选项,或在上传初始化后的任何时间(甚至在您的一个回调中)通过setParams API 方法。还有一个complete 回调将包含一个参数,该参数包含您的服务器在其响应中包含的任何数据。您可以随意使用这些数据。 API、选项、回调等都有完整的文档记录。最好的办法是从自述文件的第一页开始,并根据您的预期用途进行思考。
  • 太棒了,谢谢你的时间雷。我会研究 Fine Uploader 以及您的其他更一般的建议。如果 FU 似乎是我们的答案,我们将不得不就许可进行线下讨论。
  • 听起来不错,格雷格。您可以将许可问题发送至 license@fineuploader.com。我通常也是回答这些问题的人。 Fine Uploader 的技术支持最近移至 SO 的 Fine-uploader 标签。
猜你喜欢
  • 2021-04-15
  • 2012-12-26
  • 2017-08-30
  • 2013-01-12
  • 2012-02-01
  • 2014-06-08
  • 2016-03-09
  • 2012-10-10
  • 2012-09-08
相关资源
最近更新 更多