在使用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調用既高效又穩定,提升整體系統的可靠性。