PHP + cURL处理实时视频流问题:无限数据流适配异常
解决PHP+cURL处理无限视频流时的504超时问题
看了你的问题,核心是处理无限视频流时,PHP脚本没有持续输出数据,导致nginx触发504超时。你之前的思路没问题,但在细节配置上有几个关键疏漏,我来帮你梳理并修正:
核心问题分析
你提到的「3000万字符长字符串」是有限长度的一次性输出,而无限视频流是持续、无终止的数据流,两者的差异在于:
- 无限流需要脚本长时间运行,不能触发PHP执行超时
- 必须确保数据实时输出到客户端,不能卡在输出缓冲里
- cURL需要配置为不主动断开连接
修正后的代码实现
我调整了你的代码,解决了重复发送头、输出缓冲、超时设置等问题:
public function getStreamChunk($camera_id) { // 1. 关闭PHP执行时间限制(无限流需要持续运行) set_time_limit(0); // 2. 彻底关闭输出缓冲,确保数据实时发送 ob_end_clean(); ob_implicit_flush(true); // 3. 只发送一次响应头(重复发送会引发错误) header("Content-type: video/mp4"); header("Connection: keep-alive"); // 无限流不适合长缓存,禁用缓存避免异常 header("Cache-Control: no-cache, no-store, must-revalidate"); header("Pragma: no-cache"); header("Expires: 0"); $url = "http://example.com/$camera_id:0:0?format=mp4"; $curl = curl_init(); // 4. 优化cURL配置,适配无限流 curl_setopt_array($curl, array( CURLOPT_URL => $url, CURLOPT_HEADER => false, CURLOPT_USERPWD => "$this->login:$this->pass", CURLOPT_BUFFERSIZE => 1024 * 1024, // 保持1MB块大小 CURLOPT_WRITEFUNCTION => array($this, "callback"), CURLOPT_TIMEOUT_MS => 0, // 禁用cURL超时,让流持续传输 CURLOPT_CONNECTTIMEOUT_MS => 10000, // 连接超时设为10秒(合理值即可) CURLOPT_NOSIGNAL => true, // 避免Linux下信号中断cURL进程 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, // 强制HTTP/1.1,支持keep-alive CURLOPT_FOLLOWLOCATION => true, // 跟随源服务器的重定向(如果有) )); $result = curl_exec($curl); if (!$result) { // 错误记录到日志,避免输出到客户端破坏视频流 error_log("Curl stream error: " . curl_error($curl) . " (" . curl_errno($curl) . ")"); } curl_close($curl); } public function callback($curl, $data) { if ($data === false || $data === null) { $error = curl_error($curl) . " (" . curl_errno($curl) . ")"; error_log($error); throw new Exception($error); } $length = strlen($data); echo $data; // 强制刷新输出(即使开启了implicit_flush,保险起见加上) flush(); return $length; }
关键修改点说明
- 响应头只发送一次:你之前在回调函数里每次收到数据都发头,这会导致重复发送HTTP头的错误,虽然浏览器可能忽略,但会破坏协议规范,现在移到初始化阶段只发送一次。
- 禁用PHP执行时间限制:默认PHP脚本执行时间是30秒,无限流需要持续运行,所以用
set_time_limit(0)关闭限制。 - 关闭输出缓冲:
ob_end_clean()清空并关闭默认输出缓冲,ob_implicit_flush(true)让每次echo都自动刷新到客户端,避免数据卡在缓冲区里导致nginx超时。 - 优化cURL配置:
CURLOPT_TIMEOUT_MS => 0:让cURL不会因为超时主动断开无限流CURLOPT_NOSIGNAL => true:解决Linux下cURL可能被信号中断的问题- 强制HTTP/1.1:确保和源服务器的keep-alive连接正常工作
- 调整缓存策略:无限流没有固定长度,长缓存会导致客户端或中间节点缓存不完整的流,所以禁用缓存。
额外需要检查的配置
如果修改代码后还是出现504,可能是nginx的代理超时设置问题:
如果你的PHP脚本是通过nginx反向代理的,需要在nginx的location块里增加:
proxy_read_timeout 0; proxy_send_timeout 0;
这会关闭nginx对后端响应的超时限制,匹配无限流的需求。
关于Content-Range的说明
无限流没有总文件长度,所以不需要设置Content-Range头,源服务器也没有返回这个头,保持和源服务器一致的响应头即可,强行添加反而会引发协议错误。
内容的提问来源于stack exchange,提问作者Alex.Default
相关产品推荐
相关产品推荐

