在使用 PHP 的 cURL 扩展时,curl_multi_* 系列函数可以同时执行多个 HTTP 请求。通过 curl_multi_exec() 来批量发送请求,然后使用 curl_multi_close() 关闭句柄。虽然这些函数强大,但如果与 curl_setopt() 配合使用时,也容易出现一些坑。下面我们将讨论几个常见的错误以及如何避免它们。
当使用 curl_multi_exec() 来批量处理多个请求时,通常需要为每个请求单独设置选项。如果在添加多个句柄时没有正确设置 curl_setopt(),可能会导致请求失败或返回不正确的结果。
$ch1 = curl_init();
$ch2 = curl_init();
curl_setopt($ch1, CURLOPT_URL, 'https://gitbox.net/api/data1');
curl_setopt($ch2, CURLOPT_URL, 'https://gitbox.net/api/data2');
// 忘记设置其他必要的选项,如 CURLOPT_RETURNTRANSFER
确保在为每个 cURL 句柄设置必要的选项。例如:
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_multi_close() 和 curl_close() 都是用来关闭 cURL 句柄的,但它们的作用范围不同。curl_close() 仅关闭单个 cURL 句柄,而 curl_multi_close() 关闭一个多重 cURL 请求中的所有句柄。错误地使用这两个函数可能会导致资源未正确释放,或者程序在后续请求中出现异常。
curl_multi_close($multiHandle); // 错误,因为 $multiHandle 需要关闭的是多个句柄
在使用多重请求时,必须在完成请求并处理好每个句柄后,使用 curl_multi_close() 来关闭多个句柄:
// 执行多个请求
curl_multi_exec($multiHandle, $running);
// 关闭每个单独的 cURL 句柄
curl_close($ch1);
curl_close($ch2);
// 正确使用 curl_multi_close()
curl_multi_close($multiHandle);
有时候,开发者在使用 curl_multi_exec() 发送多个请求时,可能会因为没有正确等待请求完成而过早地关闭连接。由于 curl_multi_exec() 是异步执行的,因此需要确保所有请求都已经完成,再调用 curl_multi_close()。
// 没有等待请求完成就关闭句柄
curl_multi_close($multiHandle);
通过检测 $running 参数,确保所有请求完成后再关闭连接:
$running = null;
do {
curl_multi_exec($multiHandle, $running);
} while ($running > 0);
curl_multi_close($multiHandle);
在某些情况下,开发者可能会尝试复用同一个 cURL 句柄,这样做很容易导致请求错误或性能问题。每次发送新的请求时,都应该创建新的 cURL 句柄,并为其设置不同的选项。
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://gitbox.net/api/data1');
// 复用相同的句柄
curl_setopt($ch, CURLOPT_URL, 'https://gitbox.net/api/data2'); // 错误,应该创建新的句柄
确保为每个请求创建新的 cURL 句柄:
$ch1 = curl_init();
curl_setopt($ch1, CURLOPT_URL, 'https://gitbox.net/api/data1');
$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, 'https://gitbox.net/api/data2');
当 curl_multi_exec() 执行请求时,可能会出现各种网络或服务器错误。为了能够正确处理这些错误,应该使用 curl_error() 和 curl_errno() 来进行错误调试。
curl_multi_exec($multiHandle, $running); // 执行请求,但没有处理错误
在每个请求完成后,检查并输出错误信息:
// 执行请求
curl_multi_exec($multiHandle, $running);
// 错误处理
foreach ($handles as $ch) {
if ($errno = curl_errno($ch)) {
echo "cURL error: " . curl_error($ch);
}
}