如何从XMLHttpRequest获取进度
是否可以获取XMLHttpRequest的进度(上传的字节,下载的字节)?
当用户上传大文件时,这对于显示进度栏很有用。标准API似乎不支持它,但是也许在任何浏览器中都有一些非标准扩展?毕竟,这似乎是一个非常明显的功能,因为客户端知道上载/下载了多少字节。
注意:我知道"轮询服务器以获取进度"替代方案(这是我现在正在做的事情)。这样做的主要问题(除了复杂的服务器端代码)是,通常,在上传大文件时,用户的连接已完全断开,因为大多数ISP的上游情况较差。因此,发出额外的请求并不像我希望的那样迅速。我希望有一种方法(可能是非标准的)来获取此信息,而浏览器一直都在。
解决方案
回答
这里对AJAX模式的进度指示器进行了很好的讨论:
http://ajaxpatterns.org/Progress_Indicator
最有前途的方法之一似乎是打开第二条通向服务器的通信通道,询问服务器已完成多少传输。
回答
如果我们有权访问apache安装并信任第三方代码,则可以使用apache上载进度模块(如果使用apache;还有一个nginx上载进度模块)。
否则,我们必须编写一个脚本,可以带外使用该脚本来请求文件的状态(例如,检查tmp文件的文件大小)。
我相信在firefox 3中正在进行一些工作,我相信会为浏览器添加上载进度支持,但是这并不会渗透到所有浏览器中,并且会在一段时间内被广泛采用(更可惜)。
回答
对于上载的总数,似乎没有一种处理方法,但是有些与我们要下载的内容相似。一旦readyState为3,我们就可以定期查询responseText以下载所有内容,直到一个String为止(这在IE中不起作用),直到所有这些内容都可用时为止,然后它将转换为readyState 4. 在任何给定时间下载的字节数将等于responseText中存储的字符串中的总字节数。
对于上载问题的全有或者全无的方法,由于必须传递一个用于上载的字符串(并且可以确定该字符串的总字节数),因此为readyState 0和1发送的总字节数将为0,而为readyState发送的总字节数为0 2将是我们传入的字符串中的总字节。在readyState 3和4中发送和接收的总字节将是原始字符串中的字节总和加上responseText中的总字节。
回答
用纯JavaScript做到这一点的唯一方法是实现某种轮询机制。
我们将需要以固定的间隔(例如每5秒发送一次)发送ajax请求,以获取服务器接收到的字节数。
一种更有效的方法是使用闪存。弹性组件FileReference定期调度一个'progress'事件,该事件持有已上传的字节数。
如果我们需要坚持使用javascript,则可以在actionscript和javascript之间建立桥梁。
好消息是这项工作已经为我们完成:)
swfupload
该库允许在Flash进度事件上注册JavaScript处理程序。
该解决方案具有不需要服务器端额外资源的缺点。
回答
Firefox 3.5将支持上传进度事件
回答
Firefox支持XHR下载进度事件。
回答
对于上传的字节,这非常容易。只需监视xhr.upload.onprogress事件即可。浏览器知道它必须上传的文件的大小以及上传的数据的大小,因此它可以提供进度信息。
对于下载的字节(通过xhr.responseText获取信息时),要困难一些,因为浏览器不知道服务器请求中将发送多少字节。在这种情况下,浏览器唯一知道的就是它接收的字节大小。
有一个解决方案,在服务器脚本上设置一个" Content-Length"标头就足够了,以便获得浏览器将要接收的字节的总大小。
有关更多信息,请访问https://developer.mozilla.org/en/Using_XMLHttpRequest。
例子:
我的服务器脚本读取一个zip文件(需要5秒钟):
$filesize=filesize('test.zip'); header("Content-Length: " . $filesize); // set header length // if the headers is not set then the evt.loaded will be 0 readfile('test.zip'); exit 0;
现在,我可以监视服务器脚本的下载过程,因为我知道它的总长度:
function updateProgress(evt) { if (evt.lengthComputable) { // evt.loaded the bytes the browser received // evt.total the total bytes set by the header // jQuery UI progress bar to show the progress on screen var percentComplete = (evt.loaded / evt.total) * 100; $('#progressbar').progressbar( "option", "value", percentComplete ); } } function sendreq(evt) { var req = new XMLHttpRequest(); $('#progressbar').progressbar(); req.onprogress = updateProgress; req.open('GET', 'test.php', true); req.onreadystatechange = function (aEvt) { if (req.readyState == 4) { //run any callback here } }; req.send(); }