使用PHP代理MP4流媒体时出现“跳过代理文件”问题的技术求助
解决PHP代理MP4视频时出现“Skipping proxied MP4 file using passthru”的问题
我之前也碰到过一模一样的坑!你的代码思路是对的,但几个细节没处理到位,导致浏览器或者服务器直接跳过了代理的MP4文件。咱们一步步来修复:
问题根源分析
- 直接转发所有原服务器Header会冲突:
get_headers($url)拿到的头信息里,可能包含和你的PHP服务器环境冲突的字段(比如Connection、Transfer-Encoding),重复发送会让浏览器识别错误。 - 没处理范围请求(Range Requests):HTML5的video标签依赖断点续传和范围请求——浏览器会分段请求视频内容,而你的原代码完全没处理这个逻辑,导致浏览器直接放弃加载代理文件。
- fopen对复杂HTTP交互支持有限:
fopen在处理带特殊头的HTTP请求时,不如cURL可靠,很容易漏掉关键的响应信息。
修复后的PHP代理代码
替换你原来的fpassthru.php,用cURL来处理请求,同时支持范围请求:
<?php $targetUrl = "https://OTHER-SERVER/video.mp4"; // 初始化cURL会话,比fopen更适配HTTP复杂交互 $ch = curl_init($targetUrl); // 处理客户端的范围请求头(video标签必须的) $clientRange = $_SERVER['HTTP_RANGE'] ?? ''; if (!empty($clientRange)) { curl_setopt($ch, CURLOPT_RANGE, $clientRange); } // 配置cURL:获取响应头+响应体,不直接输出 curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_NOBODY, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $headerSize); $videoContent = substr($response, $headerSize); // 解析并发送安全的响应头,过滤冲突字段 $headerLines = explode("\r\n", $headers); foreach ($headerLines as $line) { $trimmedLine = trim($line); // 跳过会导致冲突的头 if (stripos($trimmedLine, 'Connection:') === 0 || stripos($trimmedLine, 'Transfer-Encoding:') === 0) { continue; } // 确保有效头被正确发送 if (!empty($trimmedLine)) { header($trimmedLine); } } // 输出视频内容 echo $videoContent; curl_close($ch); ?>
为什么这么改?
- 支持范围请求:处理了客户端的
HTTP_RANGE头,让浏览器可以分段加载视频,这是解决“Skipping”问题的核心。 - 过滤冲突Header:去掉了会和当前服务器环境冲突的头字段,避免浏览器收到混乱的响应信息。
- 用cURL替代fopen:cURL对HTTP协议的支持更完善,能正确处理原服务器的各种响应头和状态码。
HTML部分无需修改
你的video标签代码完全没问题,直接保留:
<video width="400" controls> <source src="http://myserver/fpassthru.php" type="video/mp4"> Your browser does not support HTML5 video. </video>
额外优化提示
- 可以添加缓存头(比如
Cache-Control: public, max-age=3600),减少重复请求原服务器,提升播放流畅度。 - 加上权限验证逻辑,比如检查当前用户是否有权限访问该视频,避免代理被滥用。
- 测试时打开浏览器开发者工具的Network标签,查看视频请求的状态码:范围请求时应该返回
206 Partial Content,完整请求时返回200 OK,这说明代理工作正常。
内容的提问来源于stack exchange,提问作者binnathon
相关产品推荐
相关产品推荐

