取消长时间运行的下载

Posted

技术标签:

【中文标题】取消长时间运行的下载【英文标题】:Cancel long running download 【发布时间】:2015-01-09 21:59:29 【问题描述】:

我在 nginx 上有一个使用 php 服务器端语言的 Web 应用程序。通过 JS,用户可以从非常慢的数据库中下载由 PHP 动态构建的文件。因此,接收第一个字节进行打印大约需要 20 秒。然后,更多的数据在之后不断流出。

PHP:

header("Content-Disposition: attachment; filename=\"" . $filename . ".txt\"");
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Set-Cookie: fileDownload=" . $filename . "; path=/");   

while (Stream::MORE_DATA == $client->receive($data)) 
   print $data;
   flush();

此下载是通过 iframe 进行的(由于其他原因,它必须保留为 iframe):

iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.src = downloadFileUrl;
(document.getElementsByTagName("body")[0]).appendChild(iframe);

如果用户想在新窗口中导航到另一个页面,则在下载完成之前不会加载另一个页面,因为 NGINX 一次只提供一个请求(我认为)。所以我为用户启用了一种取消下载的方法:

iframe.contentWindow.stop();
iframe.parentNode.removeChild(iframe);

如果在文件第一部分打印前的最初 20 秒内取消下载,则此操作成功。但是,如果在第一次打印后取消,即使 iframe 无效,文件仍会继续下载。

除了通过互联网浏览器的下载管理器手动取消下载之外,还有其他方法可以完全中止下载吗?

也许这可以通过 javascript、PHP 或 NGINX 配置更改来解决?谢谢!

【问题讨论】:

您是否考虑过在另一个浏览器窗口而不是 iframe 中进行下载?这样做将允许用户继续浏览/与页面交互,而不必担心停止下载。 感谢您的建议。我确实考虑过这样做......但是,即使请求位于单独的浏览器选项卡中,网站的其他页面也不会加载/刷新(我认为是因为 NGINX 一次只满足该 PHP 会话的一个请求) . 您确定这是 nginx 问题而不是 php 问题吗?在 php 中,如果您开始一个会话并且不结束它,那么在该请求结束之前,无法处理该会话的新请求。 php.net/manual/en/ref.session.php 见 session_write_close 我不是 php 开发人员,但是,每次使用它时,在 session_start 之后不久继续使用 session_write_close 似乎是一个好习惯,以避免类似的并发问题。打开会话,对会话变量执行所需的操作,然后关闭它。 谢谢@KevinB ...这正是我正在寻找的答案。它解决了我所有的问题。 【参考方案1】:

所以我仍然无法使用 JavaScript 来取消浏览器下载管理器中显示的已启动下载。但是,在 session_start 之后使用 session_write_close 可以避免这些并发问题,因此可以同时运行多个 PHP 脚本(即当用户在不同窗口中导航页面时仍然可以进行下载)

header("Content-Disposition: attachment; filename=\"" . $filename . ".txt\"");
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Set-Cookie: fileDownload=" . $filename . "; path=/");   

session_write_close();
while (Stream::MORE_DATA == $client->receive($data)) 
   print $data;
   flush();

【讨论】:

以上是关于取消长时间运行的下载的主要内容,如果未能解决你的问题,请参考以下文章

CancellationToken 永远不会取消我长时间运行的加载数据功能

ASP.NET Web API + 长时间运行的操作取消

如何取消 AJAX 长时间运行的 MVC 动作客户端(在 javascript 中)?

是否可以使用 iBATIS 中止长时间运行的查询?

sqlalchemy:停止长时间运行的查询

如何使用javascript在asp.net上停止正在进行的回发(长时间运行)?