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

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;
}

关键修改点说明

  1. 响应头只发送一次:你之前在回调函数里每次收到数据都发头,这会导致重复发送HTTP头的错误,虽然浏览器可能忽略,但会破坏协议规范,现在移到初始化阶段只发送一次。
  2. 禁用PHP执行时间限制:默认PHP脚本执行时间是30秒,无限流需要持续运行,所以用set_time_limit(0)关闭限制。
  3. 关闭输出缓冲:ob_end_clean()清空并关闭默认输出缓冲,ob_implicit_flush(true)让每次echo都自动刷新到客户端,避免数据卡在缓冲区里导致nginx超时。
  4. 优化cURL配置:
    • CURLOPT_TIMEOUT_MS => 0:让cURL不会因为超时主动断开无限流
    • CURLOPT_NOSIGNAL => true:解决Linux下cURL可能被信号中断的问题
    • 强制HTTP/1.1:确保和源服务器的keep-alive连接正常工作
  5. 调整缓存策略:无限流没有固定长度,长缓存会导致客户端或中间节点缓存不完整的流,所以禁用缓存。

额外需要检查的配置

如果修改代码后还是出现504,可能是nginx的代理超时设置问题:
如果你的PHP脚本是通过nginx反向代理的,需要在nginx的location块里增加:

proxy_read_timeout 0;
proxy_send_timeout 0;

这会关闭nginx对后端响应的超时限制,匹配无限流的需求。

关于Content-Range的说明

无限流没有总文件长度,所以不需要设置Content-Range头,源服务器也没有返回这个头,保持和源服务器一致的响应头即可,强行添加反而会引发协议错误。

内容的提问来源于stack exchange,提问作者Alex.Default

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:14:54