当通过代理下载的页面看起来不完整时,先看 cURL 的结果。响应过短、传输失败和完整的拦截页面需要不同的解释。

在已配置好的 handle 上启用 CURLOPT_RETURNTRANSFER 时:

$body = curl_exec($ch);
if ($body === false) {
    throw new RuntimeException(curl_error($ch), curl_errno($ch));
}

$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$downloaded = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD_T);
$declared = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T);

请在释放 handle 之前收集这些值。严格的比较能把传输失败与空字符串或 “0” 这类正常响应区分开。HTTP 错误状态并不自动等于 curl_exec 失败,所以也要解读状态码。

下载计数器不包含响应头。声明值来自 Content-Length,当大小未知时为 -1。响应完全可以合法地省略 Content-Length;未知值并不等于文件被截断的诊断。

自动内容解码还带来另一层区别。Content-Length 通常描述压缩后的表示,而 PHP 字符串可能包含解压后的字节。此时把 strlen($body) 与那个头字段比较,比较的是两种不同的表示。

当传输违反预期大小时,cURL 可能报告 CURLE_PARTIAL_FILE。请保留这个错误,而不要把任何非空输出都当成成功。反过来,一次成功的传输配上一个很小的 200 响应,也可能就是源站或代理选择返回的完整页面。

最后检查所需内容。cURL 抓取的 HTML 不会执行 JavaScript 来填充页面。即使传输的每个字节都已到达,浏览器渲染出的部分也可能不在原始响应中。

相关文章