如何从 XMLHttpRequest 获取进度

发布于 2024-07-05 12:42:48 字数 330 浏览 6 评论 0原文

是否可以获得 XMLHttpRequest 的进度(上传的字节数、下载的字节数)?

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

注意:我知道“轮询服务器进度”替代方案(这就是我现在正在做的事情)。 这样做的主要问题(除了复杂的服务器端代码之外)是,通常在上传大文件时,用户的连接完全被破坏,因为大多数 ISP 提供的上游服务很差。 因此,提出额外的请求并不像我希望的那样敏感。 我希望有一种方法(可能是非标准的)来获取浏览器始终拥有的这些信息。

Is it possible to get the progress of an XMLHttpRequest (bytes uploaded, bytes downloaded)?

This would be useful to show a progress bar when the user is uploading a large file. The standard API doesn't seem to support it, but maybe there's some non-standard extension in any of the browsers out there? It seems like a pretty obvious feature to have after all, since the client knows how many bytes were uploaded/downloaded.

note: I'm aware of the "poll the server for progress" alternative (it's what I'm doing right now). the main problem with this (other than the complicated server-side code) is that typically, while uploading a big file, the user's connection is completely hosed, because most ISPs offer poor upstream. So making extra requests is not as responsive as I'd hoped. I was hoping there'd be a way (maybe non-standard) to get this information, which the browser has at all times.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

孤独岁月 2024-07-12 12:42:48

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

更有效的方法是使用闪光灯。 Flex 组件 FileReference 定期调度“进度”保存已上传字节数的事件。
如果您需要坚持使用 JavaScript,可以在 ActionScript 和 JavaScript 之间建立桥梁。
好消息是这项工作已经为您完成了:)

swfupload

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

该解决方案的巨大优势是不需要服务器端额外的资源。

The only way to do that with pure javascript is to implement some kind of polling mechanism.
You will need to send ajax requests at fixed intervals (each 5 seconds for example) to get the number of bytes received by the server.

A more efficient way would be to use flash. The flex component FileReference dispatchs periodically a 'progress' event holding the number of bytes already uploaded.
If you need to stick with javascript, bridges are available between actionscript and javascript.
The good news is that this work has been already done for you :)

swfupload

This library allows to register a javascript handler on the flash progress event.

This solution has the hudge advantage of not requiring aditionnal resources on the server side.

瑕疵 2024-07-12 12:42:48

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

For the bytes uploaded it is quite easy. Just monitor the xhr.upload.onprogress event. The browser knows the size of the files it has to upload and the size of the uploaded data, so it can provide the progress info.

For the bytes downloaded (when getting the info with xhr.responseText), it is a little bit more difficult, because the browser doesn't know how many bytes will be sent in the server request. The only thing that the browser knows in this case is the size of the bytes it is receiving.

There is a solution for this, it's sufficient to set a Content-Length header on the server script, in order to get the total size of the bytes the browser is going to receive.

For more go to https://developer.mozilla.org/en/Using_XMLHttpRequest .

Example:
My server script reads a zip file (it takes 5 seconds):

$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;

Now I can monitor the download process of the server script, because I know it's total length:

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(); 
}
千年*琉璃梦 2024-07-12 12:42:48

Firefox 支持XHR 下载进度事件

编辑 2021-07-08 10: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/文档/Web/API/XMLHttpRequest/progress_event

Firefox supports XHR download progress events.

EDIT 2021-07-08 10:30 PDT

The above link is dead. Doing a search on the Mozilla WebDev site turned up the following link:

https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent

It describes how to use the progress event with XMLHttpRequest and provides an example. I've included the example below:

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()

I also found this link as well which is what I think the original link pointed to.

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/progress_event

遇到 2024-07-12 12:42:48

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

One of the most promising approaches seems to be opening a second communication channel back to the server to ask it how much of the transfer has been completed.

痕至 2024-07-12 12:42:48

对于上传的总数,似乎没有办法处理这个问题,但有一些类似于您想要下载的内容。 一旦readyState为3,您可以定期查询responseText以获取迄今为止以字符串形式下载的所有内容(这在IE中不起作用),直到所有内容都可用,此时它将转换为readyState 4。总计在任何给定时间下载的字节数将等于存储在responseText中的字符串的总字节数。

对于上传问题的全有或全无方法,由于您必须传递一个用于上传的字符串(并且可以确定该字符串的总字节数),因此为readyState 0和1发送的总字节数将为0,并且readyState的总字节数为0 2 将是您传入的字符串中的总字节数。readyState 3 和 4 中发送和接收的总字节数将是原始字符串中的字节数加上responseText 中的总字节数之和。

For the total uploaded there doesn't seem to be a way to handle that, but there's something similar to what you want for download. Once readyState is 3, you can periodically query responseText to get all the content downloaded so far as a String (this doesn't work in IE), up until all of it is available at which point it will transition to readyState 4. The total bytes downloaded at any given time will be equal to the total bytes in the string stored in responseText.

For a all or nothing approach to the upload question, since you have to pass a string for upload (and it's possible to determine the total bytes of that) the total bytes sent for readyState 0 and 1 will be 0, and the total for readyState 2 will be the total bytes in the string you passed in. The total bytes both sent and received in readyState 3 and 4 will be the sum of the bytes in the original string plus the total bytes in responseText.

怪我鬧 2024-07-12 12:42:48
<!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>

结果

<!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

万水千山粽是情ミ 2024-07-12 12:42:48

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

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

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

If you have access to your apache install and trust third-party code, you can use the apache upload progress module (if you use apache; there's also a nginx upload progress module).

Otherwise, you'd have to write a script that you can hit out of band to request the status of the file (checking the filesize of the tmp file for instance).

There's some work going on in firefox 3 I believe to add upload progress support to the browser, but that's not going to get into all the browsers and be widely adopted for a while (more's the pity).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文