yii2.0.55中实现视频流播放需用sendfile()自动处理range请求,将mp4放web/videos/目录,配置web服务器支持字节范围,前端video标签直连action url,禁用assetbundle和file_get_contents。

在 Yii2.0.55 中实现视频流播放,核心是绕过 PHP 文件读取的内存限制与响应阻断,直接控制 HTTP 头、分块传输和 Range 请求解析,否则大视频会触发 500 错误或下载而非播放。
准备视频文件与访问路径
将 MP4 文件放入 web/videos/ 目录(如 web/videos/demo.mp4),确保 Web 服务器能直接通过 URL 访问该路径(例如 https://yoursite.com/videos/demo.mp4)。不要放在 runtime/ 或 uploads/ 等非公开目录——浏览器无法发起 Range 请求,video 标签会卡在 loading 状态。
检查 Nginx/Apache 是否允许对 .mp4 文件启用字节范围支持:Apache 需加载 mod_headers 和 mod_mime;Nginx 默认支持,但若配置了 location ~ \.mp4$ { add_header Content-Disposition "attachment"; } 这类强制下载规则,必须删除。
创建流式响应控制器动作
在任意控制器(如 SiteController.php)中添加新动作:
public function actionVideo($name)
{
$filePath = Yii::getAlias('@webroot') . '/videos/' . basename($name);
if (!is_file($filePath) || pathinfo($filePath, PATHINFO_EXTENSION) !== 'mp4') {
throw new NotFoundHttpException('Video not found.');
}
return Yii::$app->response->sendFile($filePath, null, ['mimeType' => 'video/mp4']);
}
这一步调用 Yii 内置的 sendFile(),它已自动处理 Range 请求、Content-Range 头、206 Partial Content 响应及缓存头。无需手动解析 $_SERVER['HTTP_RANGE']——自己写容易漏掉边界校验或返回 200 而非 206,导致浏览器认为视频不可拖拽。
前端 video 标签正确写法
在视图中使用标准 HTML5 video 标签,src 指向你刚定义的动作 URL:
注意:不要用 assetBundle 发布视频文件,AssetManager 会重命名并哈希文件名,且不支持 Range 请求转发;也不要用 file_get_contents() 读取后 echo 输出——PHP 内存溢出风险极高,100MB 视频直接崩掉。
若页面嵌在 iframe 或跨域环境,需确保响应头含 Access-Control-Allow-Origin: *。可在 actionVideo() 返回前加:
Yii::$app->response->headers->set('Access-Control-Allow-Origin', '*');
验证流是否生效
打开浏览器开发者工具 → Network 标签 → 播放视频 → 找到该 MP4 请求 → 查看 Response Headers:
确认存在 Accept-Ranges: bytes 和 Content-Range(首次加载)或状态码为 206(拖动进度条时);
若始终是 200 OK 且 Content-Length 是完整文件大小,说明 Range 未生效,退回第二步检查 sendFile() 是否被中间件拦截或重写。
用 curl 手动测试:curl -I -H "Range: bytes=0-999" https://yoursite.com/site/video?name=demo.mp4
响应头应含 HTTP/1.1 206 Partial Content 及 Content-Range: bytes 0-999/12345678。











