HTTP 文件下载:监控下载进度

Posted

技术标签:

【中文标题】HTTP 文件下载:监控下载进度【英文标题】:HTTP File Download: Monitoring Download Progress 【发布时间】:2013-10-31 18:33:37 【问题描述】:

我的情况是,我必须通过 HTTP 协议从 Web 服务器下载大文件(最大 4GB):Apache 2.4.4。我尝试了几种方法,但最好的解决方案似乎是使用 X-SendFile 模块。

由于我为文件上传提供了进度条,因此我需要为文件下载提供相同的功能。所以这是我的问题:

是否有任何方法(包括变通方法)来实现文件下载进度监控? 是否有任何方法(包括解决方法)来计算文件下载传输速度? 有没有比使用 X-Sendfile 模块更好的方法从 Web 服务器提供高效的文件下载?

一般来说有没有更好的文件下载选项,可以让我监控文件下载进度?它可以是客户端 (javascript) 或服务器解决方案 (php)。是否有任何特定的网络服务器允许这样做?

目前我使用:

Apache 2.4.4 Ubuntu

非常感谢。

【问题讨论】:

您可以在 php 中使用 cURL。 ***.com/questions/13958303/… 您是否能够从服务器流式传输文件 - 或者您正在下载单个文件? @web_bod,许多文件将从服务器下载。换句话说,文件下载和上传将是服务器的主要功能。由于我控制着服务器,我可以决定任何形式的文件下载。我尝试通过 PHP 下载,但这对文件大小和下载文件数量造成了限制。因此我尝试了看起来不错的 X-SendFile。但是,如果流媒体是要走的路,我会很乐意伪造 X-SendFile @positlabs,cURL 看起来也很有趣。谢谢你的提示。由于我对 cURL 了解不多,所以我将研究它。我希望 cURL 不会对下载的文件大小或同时下载的数量造成障碍。 我会在周末为你画一些草图 - PHP 是你的首选语言吗? 【参考方案1】:

2 个想法(未验证):

第一:

不要在您的页面上放置指向文件(您要下载的文件)的常规链接,而是放置诸如 .../dowanload.php 之类的链接,这些链接可能看起来像这样:

<?php

    // download.php file
    session_start(); // if needed

    $filename = $_GET['filename']);

    header( 'Content-type: text/plain' ); // use any MIME you want here
    header( 'Content-Disposition: attachment; filename="' . htmlspecialchars($filename) . '"' );
    header( 'Pragma: no-cache' );

    // of course add some error handling

    $filename = 'c:/php/php.ini';

    $handle = fopen($filename, 'rb');

    // do not use file_get_contents as you've said files are up to 4GB - so read in chunks
    while($chunk = fread($handle, 1000)) // chunk size may depend on your filesize
    
        echo $chunk;
        flush();
        // write progress info to the DB, or session variable in order to update progress bar
    

    fclose($handle);
?>

这样您就可以密切关注您的下载过程。同时,您可以使用 AJAX 将进度信息写入 DB/session var 并从 DB/session var 更新进度条读取状态,当然还要轮询读取进度信息的脚本。

这非常简单,但我认为它可以按您的意愿工作。

第二:

Apache 2.4 内置了 Lua 语言:

mod_lua Creating hooks and scripts with mod_lua

我敢打赌,您可以尝试编写 LUA Apache 处理程序来监控您的下载 - 将进度发送到数据库并使用 PHP/AJAX 从数据库获取进度信息来更新进度条。

同样 - 有 perl 甚至 python 的模块(但不是 win)

【讨论】:

可以使用 mod_rewrite 隐藏奇怪的 URL。外界不需要知道download.php脚本。 你可以使用mod_perl来代替mod_lua,它不是处于实验状态。 使用数据库存储进度更新?我现在明白为什么 node.js 变得流行了...我的意思是至少建议 APC... @dandavis:当然,APC 没问题,但最新的 PHP 已经缺少它(Opcache 应该允许类似的事情)。 Node.js - 这是我需要阅读的更多内容 - 只是听到它 - 仅此而已。谢谢 @Artur,您好,感谢您的反馈。老实说,在我看来,这对于我需要的东西来说太复杂了,而且可能有点矫枉过正。对我有用的是fopen()fread()print() 的组合,同时使用 AJAX 请求监控下载进度。【参考方案2】:

我认为主要问题在于: 在 php+apache 解决方案中,输出缓冲可能放置在几个地方:

浏览器 Apache PHP 处理程序 PHP 解释器 进程

您需要控制第一个缓冲区。但是直接从 PHP 是不可能的。

可能的解决方案:

1) 您可以编写自己的迷你守护程序,其主要功能将仅发送文件并在例如 80 端口 8880 之外的另一个端口上运行它。并从那里处理下载文件并监视输出缓冲区。 您的输出缓冲区将只有一个,您可以控制它:

浏览器 PHP 解释器进程

2) 你也可以直接从 apache 获取 mod_lua 和控制输出缓冲区。

3) 你也可以使用 nginx 并使用内置 perl 控制 nginx 输出缓冲区(它是稳定的)

4) 尝试使用PHP Built-in web server 并直接控制php输出缓冲区。我不能说它是如何稳定的,抱歉。但是你可以试试。 ;)

我觉得nginx+php+内置perl是比较稳定和强大的解决方案。 但是您可以选择并且可能使用该列表中没有的其他解决方案。我会关注这个话题,并感兴趣地等待你的最终解决方案。

【讨论】:

【参考方案3】:

以较短的间隔读写数据库会降低性能。

我建议使用会话(增加循环中发送数据的值),您可以通过另一个 php 文件安全地关闭它,您可以将数据作为 JSON 返回,可供 javascript 函数/插件使用。

【讨论】:

好主意。我有同样的。但是,我遇到了一个意想不到的问题:当主 PHP 下载脚本正在运行时,监控 PHP 脚本不会被 AJAX 调用执行。我坚持了很长时间并对其进行了测试。但是 AJAX 监控脚本显然只有在当前没有其他 PHP 脚本运行时才会运行。 See my other post 我尝试了很多方法,但都遇到了一些问题。使用 fopen() fread() print() 的方法对我来说效果最好,并且对文件大小没有限制。因此,我将此答案标记为有用的答案,作为已接受的答案,并用我的赏金奖励它。

以上是关于HTTP 文件下载:监控下载进度的主要内容,如果未能解决你的问题,请参考以下文章

文件下载 监控 服务执行进度

如何在 iOS 6+ 中通过 SKStoreProductViewController 监控下载进度?

AFNetworking 2.0 - 在监控进度的同时批量下载图像

动态加载 JavaScript 并监控下载进度

Python HTTP下载文件并显示下载进度条

使用请求通过 http 下载文件时的进度条