使用HTTP 206 Partial Content头部时范围值异常问题排查
解决MP4视频206 Partial Content返回Content-Length不匹配问题
问题根源
你的代码存在两个核心问题,直接导致net::ERR_CONTENT_LENGTH_MISMATCH错误:
- 未初始化文件句柄:代码中直接使用
$f变量进行fseek和fread操作,但从未通过fopen打开目标文件,导致实际读取的内容长度为0,与设置的Content-Length不匹配。 - Range参数校验缺失:未对请求的Range范围做合法性校验,可能出现超出文件大小的非法范围,引发返回内容异常。
修复后的完整代码
<?php const STORAGE_PATH = '/home/files/'; $filename = "my_video.mp4"; $file = STORAGE_PATH . $filename; // 检查文件是否存在且可读 if (!file_exists($file) || !is_readable($file)) { header("HTTP/1.1 404 Not Found"); exit("File not found or unreadable"); } $size = filesize($file); $begin = 0; $end = $size - 1; header('Content-Type: video/mp4'); header('Accept-Ranges: bytes'); // 处理Range请求 if (isset($_SERVER['HTTP_RANGE'])) { $range = substr($_SERVER['HTTP_RANGE'], strpos($_SERVER['HTTP_RANGE'], '=') + 1); $rangeParts = explode('-', $range); $begin = intval($rangeParts[0]); // 处理无结束值的Range(如bytes=0-) $end = isset($rangeParts[1]) && !empty($rangeParts[1]) ? intval($rangeParts[1]) : $size - 1; // 校验Range合法性,避免越界 $begin = max(0, min($begin, $size - 1)); $end = max($begin, min($end, $size - 1)); $length = $end - $begin + 1; header('HTTP/1.1 206 Partial Content'); header("Content-Range: bytes $begin-$end/$size"); } $length = $end - $begin + 1; header('Content-Length: ' . $length); header('Content-Disposition: inline; filename="' . $filename . '"'); // 打开文件并定位到起始位置 $f = fopen($file, 'rb'); fseek($f, $begin); // 分块输出文件内容,避免内存溢出 while ($length > 0) { $chunkSize = min(1024 * 1024, $length); // 每次输出1MB echo fread($f, $chunkSize); $length -= $chunkSize; flush(); } fclose($f); exit(); ?>
关键修复点说明
- 文件存在性检查:先验证文件是否存在且可读,避免后续操作报错。
- 初始化文件句柄:通过
fopen($file, 'rb')以二进制只读模式打开文件,确保能正确读取内容。 - Range合法性校验:强制将
$begin和$end限制在合法范围内,防止请求超出文件大小的范围。 - 分块输出内容:大文件直接
fread可能导致内存溢出,分块输出更稳定。 - 清理冗余代码:移除重复的
$length计算,逻辑更清晰。
错误触发原因解释
当浏览器发送Range: bytes=0-请求时,你的代码虽然计算了正确的Content-Length,但由于未打开文件,fread($f, $length)返回空内容,实际输出的内容长度为0,与头部声明的Content-Length不一致,浏览器因此抛出net::ERR_CONTENT_LENGTH_MISMATCH错误。
内容的提问来源于stack exchange,提问作者Phaelax
相关产品推荐
相关产品推荐

