xhr2文件上传 - 使用formData访问文件名

问题描述:

我有一个上传组件到我的应用程序,它成功地在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

如果你想发送一个请求中的所有文件,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