从服务器下载文件时显示进度条

13

我需要向请求下载文件的用户展示进度条。 我正在使用J2EE应用程序生成文件。 用户将提交表单数据以获取文件。 服务器接收所有提交的数据,进行操作,生成并将PDF文件发送回客户端。

因此,我想在文件到达客户端之前向用户显示进度条。有没有办法做到这一点?


2
我非常想知道如何做到这一点。 - Lauri Lehtinen
通常生成文件需要多长时间? - cherouvim
@cherouvim:这里的时间不是静态的,它因文件而异。它需要最少1秒钟,最多20-30分钟的时间。 - Puru
4个回答

10

如果我理解得正确,您想要显示一个进度条直到服务器准备好发送文件,而不是显示文件下载的进度。

如果是这样,您正在处理一项棘手的练习。可靠的进度条需要知道您要做什么以及需要多长时间(非常精确)。在您的情况下,有很多不可靠的因素(其中之一,可能是最大的因素,是网络本身)。

因此,大多数开发人员使用某种“无限”动画来显示“工作正在进行中”。

更新

根据您的评论,显示“工作正在进行中”动画的最简单方法如下:

$.ajax({
    url:      "/myscripts/myserverscript",
    type:     "POST",
    data:     {
       foo: "bar"
    },
    dataType: "text",
    beforeSend: function(xhr){
        // display a progress animation
    },
    complete: function(xhr, status){
        // hide the animation
    }
    ...
});
在单个请求的情况下,您还可以设置全局的ajax事件处理程序来设置显示/隐藏功能(.ajaxStart().ajaxStop())。
参考资料:.ajax().ajaxStart().ajaxStop()

任何一种情况都是有效的。了解正在下载的文件的进度将是很好的。或者,我仍然可以通过显示一个工作进度条来表明服务器准备好发送文件。 - Puru
1
如何在ajax成功方法中设置文件下载。我能够将文件获取到客户端,但不知道如何强制浏览器下载。 - Puru

4

服务器端文件生成进度条:

我们假设服务器需要花费很多秒来生成文件。这个事件由原始请求触发,是一个阻塞操作。当它完成时,文件将被生成并发送回客户端。

同时,您希望通过其他请求(ajax)调用服务器,并获取针对当前正在为特定用户生成的文件的百分比。

这里的关键部分是:

  • 当原始请求正在生成文件时,它需要在频繁的间隔(例如每10%)中存储进度。将此数据存储在HTTP会话中可以正常工作。
  • 其他请求(ajax)只需能够从HTTP会话中提取此信息
  • 在HTTP会话上进行同步(串行访问),这是一些Web应用程序通常做的事情,但不可行,因为其他请求(ajax)将简单地阻塞,直到原始请求完成
  • 在客户端,所有交互都是基于html+javascript,以提供所需的交互(动画进度条)。即使时间间隔非常粗略(跳过10%到20%再到30%),您也可以使用jQuery动画显示该进度条。我曾经做过一次,效果非常好。

文件下载进度条:

最好将其留给浏览器的本机对话框。


请问您是如何从HTML/JavaScript中获取文件下载信息的?您能否分享一些关于您上次提到的最后一点的更多信息吗?(在客户端,这一切都是......) - Puru
在服务器端,您需要一个URL(例如Java servlet)来提供此信息(仅从http会话中打印百分比)。无论这是纯文本(例如“20%”)还是JSON或XML,都取决于您以及如何实现客户端。在客户端上,您将通过jQuery对URL执行异步请求,以获取此信息并相应地修改DOM。请求将需要每X秒(假设为3秒)通过javascript函数setTimeout(..)触发。 - cherouvim
对于这种方法,我真的建议使用某种COMET方式,而不是原生的ajax请求。 - jAndy
感谢您的有效输入。 - Puru

0

使用XMLHttpRequest,您可以下载文件并显示进度。

showProgressBar(); 
var xhr = new XMLHttpRequest();
xhr.open("GET", 'https://upload.wikimedia.org/wikipedia/commons/d/dd/Big_%26_Small_Pumkins.JPG', true);
xhr.responseType = "blob";
xhr.onprogress = function (e) {
    console.log(e.loaded / e.total * 100);//shows downloaded percentage
    setProgressBarPercentage(e.loaded / e.total * 100);
}
xhr.onload = function () {
    hideProgressBar();
    var urlCreator = window.URL || window.webkitURL;
    var url = urlCreator.createObjectURL(this.response);
    var link = document.createElement('a');
    link.setAttribute('href', url);
    link.setAttribute('download', 'FILENAME');
    link.click();
}
xhr.send();

0
在Java中,您只需将javax.swing.ProgressMonitorInputStream包装在输入流周围,但要注意,除非服务器以分块流模式发送,否则显示实际上并没有什么意义,因为在将第一个字节传递到Java之前,整个响应将被读入内存。

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