使用XmlHttpRequest发送文件:流传输?

14

我正在尝试使用拖放上传大文件。 我有这段JavaScript代码:

xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('X-File-Size', file.size);
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);

url是目标URL的字符串,file是一个Blob(根据http://www.w3.org/TR/XMLHttpRequest2/#the-send-method),我在文件拖放后检索到它。该代码适用于Chrome 12、Safari 5和Firefox 4,并将文件的原始内容发送到HTTP请求的主体中。

但是,如果文件足够大,则永远不会发送请求。相反,XMLHttpRequest对象触发了错误事件(没有任何有用的消息)。在我的环境中,这个限制为86MB,但它因机器而异。

Chrome的JavaScript控制台显示以下消息:

POST http://localhost/xfiles/xfiles.php undefined (undefined)

这与我的代码无关(适用于小文件的代码完美运行)。

浏览器似乎会在发送文件之前将整个文件读入内存。可能出现内存不足异常或类似情况导致进程停止。无论如何,没有HTTP请求被发送,所以可以确定服务器限制与此问题无关。

总之,读取整个文件是一种浪费资源的行为

是否有任何方法以流式方式按字节发送文件,而无需首先将其存储在内存中?

2个回答

10

尝试使用Blob.slice方法将Blob分割成多个块,并将每个块作为单独的请求发送。


1
我刚刚使用Blob.slice实现了解决方案,即使处理4GB的文件也完美运行!非常感谢。 - linepogl
6
请问您能否给我一个例子,展示如何对blob进行切片并发送多个块。谢谢 :) - TaeV
如何将每个请求单独发送?是否可以只使用同一个XMLHttpRequest对象?还是每个数据块都需要创建一个新的对象? - Green
我认为你需要为每个请求创建一个新的XMLHttpRequest对象。基本上,你需要将文件分割成多个部分,将每个部分作为单独的HTTP请求发送,并在服务器上将它们拼接回来。 - Na7coldwater
@Na7coldwater 你会如何在服务器上识别通信?使用一个大的随机字符串吗? - user877329

9
今天,在chrome 31(windows)中,xhr.send(file)不会将整个文件读入内存。事实上,我尝试发送100mb的文件,并查看Chrome内存使用情况 - 在100mb文件上传期间,它只略微增长。
顺便说一句,xhr.send(file)更适合PUT上传,对于POST更适合使用FormData:
  var formData = new FormData();
  formData.append("thefile", file);
  xhr.send(formData);

然而,使用FormData会增加上传时间约50% - 可能是因为base64编码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接