如何从 XMLHttpRequest 获得进展

是否有可能获得 XMLHttpRequest 的进度(上传字节,下载字节) ?

这对于用户上传大文件时显示进度条非常有用。标准的 API 似乎并不支持它,但是也许在其他浏览器中有一些非标准的扩展?毕竟,这似乎是一个非常明显的特性,因为客户机知道上传/下载了多少字节。

注意: 我注意到了“轮询服务器以获得进展”的替代方法(这就是我现在正在做的)。这样做的主要问题(除了复杂的服务器端代码)是,通常,当上传一个大文件时,用户的连接完全失效,因为大多数 ISP 提供的上行代码很差。所以提出额外的要求并不像我希望的那样有效。我希望有一种方法(也许是非标准的)可以获得这些信息,而浏览器一直都有这些信息。

156141 次浏览

最有希望的方法之一似乎是打开第二个通信通道回到服务器,询问它已经完成了多少传输。

如果可以访问 apache 安装并信任第三方代码,则可以使用 Apache 上传进度模块(如果使用 apache,还有一个 上传进度模块)。

否则,您必须编写一个可以在带外点击的脚本来请求文件的状态(例如,检查 tmp 文件的文件大小)。

我相信 Firefox 3正在进行一些工作,以增加对浏览器的上传进度支持,但这不会进入所有的浏览器,并被广泛采用一段时间(更多的是遗憾)。

对于总上传似乎没有一个方法来处理这一点,但有一些类似的东西,你想要下载。当 readyState 为3时,您可以周期性地查询 responseText 以获得所有下载的内容(在 IE 中不起作用) ,直到所有内容都可用时,它才会转换到 readyState 4。在任何给定时间下载的总字节数将等于在 responseText 中存储的字符串中的总字节数。

对于上传问题的 all 或 nothing 方法,因为必须传递一个字符串用于上传(并且可以确定其总字节数) ,所以为 readyState 0和1发送的总字节数为0,为 readyState 2发送的总字节数为您传递的字符串中的总字节数。在 readyState3和 readyState4中发送和接收的总字节数将是原始字符串中的字节数之和加上 response seText 中的总字节数。

使用纯 javascript 的唯一方法是实现某种轮询机制。 您需要以固定的间隔(例如每5秒)发送 ajax 请求,以获取服务器接收到的字节数。

更有效的方法是使用 flash。Flex 组件 文件参考定期发送一个“进度”事件,其中包含已经上传的字节数。 如果您需要坚持使用 javascript,那么 actionscript 和 javascript 之间可以使用桥接。 好消息是这项工作已经为你做好了:)

开始

这个库允许在 flash 进度事件上注册一个 javascript 处理程序。

这种解决方案的优点是不需要服务器端的其他资源。

Firefox 支持 XHR 下载进度事件

EDIT 2021-07-0810:30 PDT 编辑2021-07-0810:30 PDT

上面的链接已经死了,在 Mozilla WebDev 网站上搜索一下就会出现以下链接:

Https://developer.mozilla.org/en-us/docs/web/api/progressevent

它描述了如何在 XMLHttpRequest 中使用进度事件,并提供了一个示例:

var progressBar = document.getElementById("p"),
client = new XMLHttpRequest()
client.open("GET", "magical-unicorns")
client.onprogress = function(pe) {
if(pe.lengthComputable) {
progressBar.max = pe.total
progressBar.value = pe.loaded
}
}
client.onloadend = function(pe) {
progressBar.value = pe.loaded
}
client.send()

我也发现了这个链接,这也是我认为原始链接所指向的。

Https://developer.mozilla.org/en-us/docs/web/api/xmlhttprequest/progress_event

对于上传的字节来说,这很容易。只要监控 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();
}

<!DOCTYPE html>
<html>
<body>
<p id="demo">result</p>
<button type="button" onclick="get_post_ajax();">Change Content</button>
<script type="text/javascript">
function update_progress(e)
{
if (e.lengthComputable)
{
var percentage = Math.round((e.loaded/e.total)*100);
console.log("percent " + percentage + '%' );
}
else
{
console.log("Unable to compute progress information since the total size is unknown");
}
}
function transfer_complete(e){console.log("The transfer is complete.");}
function transfer_failed(e){console.log("An error occurred while transferring the file.");}
function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}
function get_post_ajax()
{
var xhttp;
if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers}
else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5
xhttp.onprogress = update_progress;
xhttp.addEventListener("load", transfer_complete, false);
xhttp.addEventListener("error", transfer_failed, false);
xhttp.addEventListener("abort", transfer_canceled, false);
xhttp.onreadystatechange = function()
{
if (xhttp.readyState == 4 && xhttp.status == 200)
{
document.getElementById("demo").innerHTML = xhttp.responseText;
}
};
xhttp.open("GET", "http://it-tu.com/ajax_test.php", true);
xhttp.send();
}
</script>
</body>
</html>

Result