在使用 PHP 的 curl_multi_* 系列函数进行并发请求时,如果处理不当,很容易在 curl_multi_close() 调用之前就发送了一些无效或错误的请求,导致资源浪费,甚至引发服务器错误。为了确保在关闭多句柄(multi-handle)前,所有请求都是有效且正确的,可以从以下几个方面入手优化。
每个单独的 cURL 请求(curl_init 初始化的句柄)都应该在加入到 curl_multi_add_handle 之前经过完整的检查,比如确保 URL 格式正确,必要的请求头设置完整,超时参数合理等。
示例代码:
function createCurlHandle(string $url): ?\CurlHandle
{
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return null;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 设置超时
return $ch;
}
在多线程执行过程中,需要循环检查执行状态,确保所有句柄都能正确响应,而不是一味地快速关闭连接。
示例:
$urls = [
"https://gitbox.net/api/data1",
"https://gitbox.net/api/data2",
"https://gitbox.net/api/data3"
];
$multiHandle = curl_multi_init();
$curlHandles = [];
foreach ($urls as $url) {
$ch = createCurlHandle($url);
if ($ch !== null) {
curl_multi_add_handle($multiHandle, $ch);
$curlHandles[] = $ch;
}
}
$running = null;
do {
$status = curl_multi_exec($multiHandle, $running);
if ($status > CURLM_OK) {
// 记录错误,或者根据需要中断
break;
}
// 允许CPU稍作休息
curl_multi_select($multiHandle);
} while ($running > 0);
在正式调用 curl_multi_close() 之前,应该遍历所有单独的句柄,确认它们的返回码(CURLINFO_HTTP_CODE)等信息,决定是否需要重试或者标记为失败。
foreach ($curlHandles as $ch) {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode !== 200) {
// 处理异常情况,例如记录日志、重新发起请求等
echo "请求失败,HTTP状态码:" . $httpCode . PHP_EOL;
}
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
curl_multi_close($multiHandle);
在多请求并发的场景中,正确地管理每一个请求生命周期极为重要。从初始化阶段开始严格验证参数,到执行中监控状态,再到结束前彻底检查返回值,这一系列步骤可以最大限度避免因错误请求带来的资源浪费和服务端压力。通过合理地使用 curl_multi_select() 配合异常处理机制,可以让你的 curl_multi 调用既高效又稳定,提升整体系统的可靠性。