把响应头各行的收集与响应正文分开。经由代理的传输可能在一次操作中先后交付 CONNECT、认证、重定向和目标站点的响应头:

$headerLines = [];
curl_setopt($handle, CURLOPT_HEADERFUNCTION,
    function ($handle, $line) use (&$headerLines) {
        $headerLines[] = $line;
        return strlen($line);
    }
);

这个回调保留原始的行的顺序,并返回已接受的字节数。它收到的是完整行;但此时还没有把它们归组为响应,也没有选出最终站点的响应头。

把这个序列按块来解读

HTTP 状态行开始一个响应块,空行结束该块的响应头。在选定最终的目标响应之前,要先保留这些边界。中途的认证尝试和重定向都可能各自追加块。

尾部字段(trailer)可能稍后经由回调到达。要保留足够的解析器状态,把它们与初始响应头区分开,而不是把后续每个字段都挂到第一个响应上。

保留或抑制隧道证据

CURLINFO_HTTP_CONNECTCODE 单独读取 HTTPS 隧道的 CONNECT 状态。隧道被接受并不代表站点响应成功。

如果采集端不需要 CONNECT 头,CURLOPT_SUPPRESS_CONNECT_HEADERS 控制它们是否进入配置的响应头输出和回调路径。请检查所链接的 libcurl 与 PHP 构建是否支持。抑制能简化采集,但会去掉有助于诊断的响应头级隧道证据。

不要用固定偏移量、也不要靠查找某个 HTML 标签来取回正文。响应头长度会变,中间响应各不相同,正文还可能是二进制或空的。某个旧版本的特定缺陷报告不足以支持猜测的偏移量。

正文处理要分开,采集或解析失败时要把传输错误连同观察到的响应阶段一起保留下来。这样才能区分回调被中断、应用数据格式错误和被拒绝的代理交换。

相关文章