You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现网页端4-20GB大视频文件的可靠下载?

大文件(4-20GB)下载的可靠实现方案

针对你遇到的大文件下载中断、浏览器崩溃等问题,以下是经过验证的解决思路和具体实现方法:

一、先明确你之前方案失效的核心原因

  • readfile方法中断:PHP默认的内存限制、执行时间限制会导致大文件一次性读取失败,且未处理断点续传,一旦中断只能重新开始。
  • 分块下载浏览器崩溃:大概率是分块逻辑未正确处理HTTP Range请求,或者块大小设置不合理(比如单次读取过大导致内存溢出),也可能是HTTP响应头缺失关键字段(如Accept-Ranges)。
  • X-Sendfile失效:该方法依赖服务器模块支持(Apache的mod_xsendfile、Nginx的X-Accel-Redirect),未配置则完全无效。

二、推荐的可靠方案

方案1:优化PHP分块下载(支持断点续传)

这种方案无需修改服务器配置,适合无法操作服务器环境的场景,核心是逐块读取文件、处理断点续传请求、避免内存积压。

示例代码:

<?php
$file = '/path/to/your/large-video.mp4';
$filename = basename($file);
$filesize = filesize($file);

// 处理断点续传的Range请求
$range = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : false;
if ($range) {
    list($param, $range) = explode('=', $range);
    if (strtolower(trim($param)) !== 'bytes') {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        header("Content-Range: bytes */$filesize");
        exit;
    }
    list($start, $end) = explode('-', $range);
    $start = (int)$start;
    $end = $end ? (int)$end : $filesize - 1;
    if ($start >= $filesize || $end >= $filesize) {
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        header("Content-Range: bytes */$filesize");
        exit;
    }
    $length = $end - $start + 1;
    header("HTTP/1.1 206 Partial Content");
    header("Content-Length: $length");
    header("Content-Range: bytes $start-$end/$filesize");
} else {
    $length = $filesize;
    header("Content-Length: $length");
}

// 设置必要的响应头
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: no-cache');
header('Pragma: no-cache');

// 禁用PHP执行时间限制
set_time_limit(0);
// 关闭输出缓冲
ob_end_clean();
flush();

// 逐块读取并输出文件
$chunkSize = 1024 * 1024; // 每次读取1MB
$handle = fopen($file, 'rb');
fseek($handle, $start ?? 0);
while (!feof($handle) && ($length > 0)) {
    $read = min($chunkSize, $length);
    echo fread($handle, $read);
    flush();
    $length -= $read;
}
fclose($handle);
exit;

关键注意点:

  • 设置set_time_limit(0)避免脚本超时
  • 关闭输出缓冲ob_end_clean(),防止缓冲区满导致卡顿
  • 每次读取小块(1MB左右),避免内存占用过高
  • 正确处理Range请求,支持断点续传

方案2:配置服务器原生X-Sendfile/X-Accel-Redirect(最优性能)

这种方案让Web服务器直接处理文件传输,PHP仅负责权限验证等逻辑,性能最高,完全避免PHP内存/超时问题。

Apache环境:

  1. 安装mod_xsendfile模块(不同系统包管理器不同,比如Ubuntu用apt install libapache2-mod-xsendfile)
  2. 在Apache配置文件(httpd.conf)或站点.htaccess中添加:
    XSendFile On
    XSendFilePath /path/to/your/video/directory
    
  3. PHP代码中只需设置头信息:
    <?php
    // 此处可添加权限验证逻辑
    $file = '/path/to/your/large-video.mp4';
    $filename = basename($file);
    header('Content-Type: video/mp4');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    header('X-Sendfile: ' . $file);
    exit;
    

Nginx环境:

  1. 在Nginx配置文件的server块中添加内部跳转规则:
    location /internal-download {
        internal;
        alias /path/to/your/video/directory;
        add_header Content-Disposition 'attachment; filename="$basename"';
    }
    
  2. PHP代码中设置跳转头:
    <?php
    // 此处可添加权限验证逻辑
    $filename = 'large-video.mp4';
    header('Content-Type: video/mp4');
    header('X-Accel-Redirect: /internal-download/' . $filename);
    exit;
    

方案3:直接通过Web服务器提供下载(无需PHP)

如果文件无需权限验证,可直接配置Web服务器映射文件目录,让服务器原生处理下载,性能最优。

Nginx示例:

location /public-videos {
    alias /path/to/your/video/directory;
    autoindex off;
    add_header Content-Disposition 'attachment; filename="$basename"';
    # 支持断点续传的默认配置
    mp4;
}

用户访问http://yourdomain/public-videos/large-video.mp4即可直接下载,Nginx会自动处理断点续传、分块传输。

三、额外注意事项

  • 确保服务器磁盘IO带宽充足,大文件下载对IO压力较大,可考虑使用SSD存储
  • 测试断点续传功能:用curl -H "Range: bytes=1000000-" http://yourdomain/download.php验证是否能从指定位置继续下载
  • 检查PHP配置:memory_limit无需过高(分块读取时128MB足够),output_buffering设为Off

内容的提问来源于stack exchange,提问作者user24772931

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:53:10