HTML5 应用案例:Box.net 和 HTML5 拖放

这是来自 Tomas Barreto 的客座文章,他是一位在 box.net 工作的开发者。他们最近采用了 HTML5 拖放作为一种通过 Firefox 中的新功能与其他人共享文件的方式。视频展示了该功能和服务的演示,同时说明了使用 HTML5 进行简单的多文件上传进度展示是多么容易。Tomas 概述了执行此操作所需的相对简单的 JavaScript 代码,以及 Firefox 4 中的改进将如何使事情变得更加容易。在文章底部查看更多文档和资源的链接。

在 Box.net,我们一直在探索新的方法,帮助用户快速安全地将内容上传到我们的云内容管理平台。因此,当在 4 月份的 Box Hack Olympics 中被问及,“什么功能会让你更多地使用 Box?”时,我的同事 CJ 和我决定采用最直观的文件上传方式:简单地将它们从桌面拖放到 Box 中。

我们考虑过从 Gears 到 Firefox 插件的各种技术,但只有 HTML5 拥有足够的普及度。通过使用 HTML5 标准中定义的一些 JavaScript API,CJ 和我能够为支持的浏览器中的用户创建无缝的拖放体验。此外,使用基于 HTML5 的上传功能使我们能够让用户一次选择多个文件,并无需轮询即可在客户端显示进度。随着 HTML5 在前四名浏览器中最新版本的普及,我们对构建基于此新技术的文件上传方法充满信心,而且不用像使用第三方插件那样做出妥协。

几周前我们发布了第一个拖放功能版本,我们对它的快速普及印象深刻。它已经成为将文件上传到 Box 的最受欢迎方式之一,并且在第一周就超过了我们之前使用的 AJAX 上传方法。你可以观看我们的演示视频,感受一下这个功能。

为了构建这个功能,我们参考了一些在线示例,这些示例解释了如何使用 Firefox 3 FileReader 对象和拖放文件事件支持。我们第一个实现使用此对象将文件加载到内存中,然后利用最新的 XMLHttpRequest 事件来跟踪客户端上的进度。

var files = event.originalEvent.dataTransfer.files; // drop event
var reader = new FileReader();

reader.onload = function(event) {
  var file_contents = event.target.result;
  var request = new XMLHttpRequest();

  ... // attach event listeners to monitor progress and detect errors

  var post_body = '';

  .. // build post body

  post_body += file_contents;

  .. // finish post body

  var url = 'http://example.com/file_upload';

  var request = new XMLHttpRequest();

  request.open("POST",  url, true); // open asynchronous post request
  request.setRequestHeader('content-type', 'multipart/form-data; boundary=""'); // make sure to set a boundary
  request.send(post_body);
}

reader.readAsBinaryString(files[0]);

这种方法运行良好,因为我们可以使用之前用于上传的相同服务器处理代码。这里的主要缺点是 FileReader 对象将整个文件读入内存,这对于一般的上传用例来说不是最佳的。我们当前的 HTML5 实现使用了这种逻辑,并且迫使我们将拖放上传限制为只有 25MB。但是,由于 Mozilla 团队的建议,我们将在拖放的 V2 版本中采用另一种方法,其中文件将按请求需要的方式分块读取。下面是我们如何做到的。

var files = event.originalEvent.dataTransfer.files; // drop event
var url = 'http://example.com/file_upload';

var request = new XMLHttpRequest();
request.open("POST",  url, true); // open asynchronous post request
request.send(files[0]);

由于这种方法不是格式化为 multipart form-data,因此需要对我们的后端进行一些调整,以支持以这种方式接收文件上传。但是,这绝对值得权衡,因为我们将获得之前方法的所有好处,并且不需要特殊的文件大小限制。将来,我们将考虑使用 另一种在 Firefox 4 中支持且使用传统多部分表单的有效上传文件的方式

var files = event.originalEvent.dataTransfer.files; // drop event
var url = 'http://example.com/file_upload';

var request = new XMLHttpRequest();

var fd = new FormData;
fd.append("myFile", files[0]);

request.open("POST",  url, true); // open asynchronous post request
request.send(fd);

我们已经在探索更多方法,使用 HTML5 来丰富 Box 体验。使用 HTML5,我们可以使用原生浏览器支持构建更快、更丰富、更具交互性的功能,并缩短桌面软件和 Web 应用程序之间的传统差距。以下是我们路线图中一些与上传相关的酷炫新功能。

  • 使用 Blob 切片 API 暂停/恢复上传,将文件分割成块(这将极大地提高鲁棒性,特别是对于大型上传)。
  • 允许即使在浏览器关闭后也恢复上传,方法是使用 IndexedDB 支持(可能在 Firefox 4 中)缓存文件。

我们还想开始讨论支持反向拖放用例:将文件从浏览器拖放到桌面。根据用户对拖放上传功能的热情,我们认为反向功能会受到欢迎。如果你有兴趣为这项功能的规范做出贡献,请告诉我们 (html5 [-at$] box.net)!

资源


12 条评论

  1. wildanr05

    迫不及待地想看到反向拖放的实现。

    2010 年 6 月 24 日 18:51

  2. SanderT

    我实现了与本文中描述的相同 V1 解决方案(通过使用 FileReader),因此我很惊讶地看到 V2 版本中描述了一个更简单的解决方案(通过在 request.send 中直接使用 files[0])。但是该解决方案不起作用,我认为是因为当前 Firefox 实现 (3.6) 中的 File 对象尚未使用 Blob 对象。因此,要使用此解决方案,我们必须等到 Firefox 4.0。有人可以确认我的结论吗?

    2010 年 6 月 25 日 02:14

    1. SanderT

      Oops.. 我没有在 3.6 中测试,而是在 3.5 中测试了 :-( 我的错.. 在 3.6 中,V2 解决方案运行良好… :-)

      2010 年 7 月 23 日 03:01

  3. arieff

    结果在哪里?

    2010 年 6 月 26 日 23:07

  4. len

    V2 解决方案(在不使用 FileReader 的情况下发送 File 对象)确实有效,但内容不会作为 multipart/form-data 发送,因此后端需要略微不同。在 PHP 中,数据可以通过 php://input 而不是 $_FILES 获得。

    2010 年 7 月 1 日 14:29

  5. Ryan

    很棒的工作,很高兴看到拖放功能在实际产品中得到使用。

    2010 年 7 月 4 日 22:40

  6. ardhan

    我正在等待 HTML 6 的发布。

    2010 年 7 月 7 日 22:55

  7. det

    看起来很简单,只需拖放即可。

    2010 年 7 月 18 日 23:04

  8. Komrade Killjoy

    HTtp 不适合文件共享。那是 *另一个* 协议的作用 *。

    Ftp

    :-P

    2010 年 7 月 28 日 05:52

  9. Dave Merrill

    在我的应用程序在 Firefox 3.6 中使用这些技术正常运行后,它在 Firefox 4 RC1 中不再工作。当我将文件拖放到放置区域时,现在显示一个“取消”光标。这是故意的吗?现在我们需要做些什么才能启用来自文件系统的放置?还是这是预发布的错误?

    谢谢,
    Dave

    2011 年 3 月 17 日 04:32

  10. David

    这救了我的命

    var fd = new FormData;
    fd.append(“myFile”, files[0]);

    非常好的代码 :)

    2011 年 7 月 6 日 06:52

  11. Yasin

    “我正在等待 HTML 6 的发布”对我来说 :)

    2011 年 12 月 24 日 05:51

本文的评论已关闭。