curl_errno() 函数用于返回最后一次cURL操作的错误代码。与curl_error()返回可读的错误描述不同,curl_errno()返回一个数字代码,便于程序进行精确的错误识别和分类处理。
int curl_errno ( resource $ch )
| 参数 | 描述 | 类型 | 必需 |
|---|---|---|---|
| ch | 由 curl_init() 返回的cURL句柄 |
resource | 是 |
返回错误代码的整数值。如果没有错误发生,返回 0 (CURLE_OK)。
| 错误代码 | 常量 | 描述 | 解决方案 |
|---|---|---|---|
| 1 | CURLE_UNSUPPORTED_PROTOCOL | 不支持的协议 | 检查URL协议是否支持(http/https) |
| 6 | CURLE_COULDNT_RESOLVE_HOST | 无法解析主机 | 检查域名拼写和DNS设置 |
| 7 | CURLE_COULDNT_CONNECT | 无法连接到服务器 | 检查网络连接和服务器状态 |
| 28 | CURLE_OPERATION_TIMEDOUT | 操作超时 | 增加超时时间或优化网络 |
| 35 | CURLE_SSL_CONNECT_ERROR | SSL连接错误 | 检查SSL证书设置 |
| 47 | CURLE_TOO_MANY_REDIRECTS | 重定向过多 | 检查重定向循环或限制重定向次数 |
| 52 | CURLE_GOT_NOTHING | 服务器未返回任何数据 | 检查服务器响应和连接稳定性 |
| 56 | CURLE_RECV_ERROR | 接收网络数据失败 | 检查网络连接稳定性 |
| 60 | CURLE_SSL_CACERT | SSL证书问题 | 验证SSL证书或禁用验证(仅开发) |
| 特性 | curl_errno() | curl_error() |
|---|---|---|
| 返回值类型 | 整数(错误代码) | 字符串(错误描述) |
| 主要用途 | 程序逻辑判断和错误分类 | 显示给开发人员或记录日志 |
| 无错误时的返回值 | 0 (CURLE_OK) | 空字符串 ("") |
| 国际化支持 | 代码是固定的,不受语言影响 | 描述文本可能随系统语言变化 |
| 推荐使用场景 | 条件判断、错误分类、自动化处理 | 调试信息、用户提示、日志记录 |
@php
// 初始化cURL会话
$ch = curl_init();
// 设置一个可能出错的URL
curl_setopt_array($ch, [
CURLOPT_URL => "https://invalid-domain-12345.com",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5
]);
// 执行请求
$response = curl_exec($ch);
// 检查错误代码
$errorCode = curl_errno($ch);
if ($errorCode !== 0) {
// 获取错误描述
$errorMessage = curl_error($ch);
echo "cURL请求失败!\n";
echo "错误代码: " . $errorCode . "\n";
echo "错误描述: " . $errorMessage . "\n";
// 根据错误代码进行特定处理
switch ($errorCode) {
case CURLE_COULDNT_RESOLVE_HOST: // 6
echo "处理: 域名解析失败,检查域名拼写\n";
break;
case CURLE_OPERATION_TIMEDOUT: // 28
echo "处理: 请求超时,尝试增加超时时间\n";
break;
case CURLE_SSL_CONNECT_ERROR: // 35
echo "处理: SSL连接错误,检查证书设置\n";
break;
default:
echo "处理: 未知错误,查看cURL文档了解错误代码 " . $errorCode . "\n";
}
} else {
echo "请求成功!\n";
echo "响应长度: " . strlen($response) . " 字节\n";
}
curl_close($ch);
@endphp
@php
class CurlErrorHandler {
// 可重试的错误代码
const RETRYABLE_ERRORS = [
CURLE_COULDNT_CONNECT, // 7
CURLE_OPERATION_TIMEDOUT, // 28
CURLE_GOT_NOTHING, // 52
CURLE_RECV_ERROR, // 56
CURLE_SEND_ERROR // 55
];
// 配置错误
const CONFIGURATION_ERRORS = [
CURLE_UNSUPPORTED_PROTOCOL, // 1
CURLE_URL_MALFORMAT, // 3
CURLE_SSL_CACERT // 60
];
// 网络错误
const NETWORK_ERRORS = [
CURLE_COULDNT_RESOLVE_HOST, // 6
CURLE_COULDNT_CONNECT // 7
];
public static function handleCurlError($ch, $url) {
$errorCode = curl_errno($ch);
$errorMessage = curl_error($ch);
echo "URL: {$url}\n";
echo "错误代码: {$errorCode}\n";
echo "错误描述: {$errorMessage}\n";
$category = self::categorizeError($errorCode);
$action = self::getRecommendedAction($category, $errorCode);
echo "错误分类: {$category}\n";
echo "推荐操作: {$action}\n";
return [
'code' => $errorCode,
'message' => $errorMessage,
'category' => $category,
'action' => $action
];
}
private static function categorizeError($errorCode) {
if ($errorCode === 0) {
return 'success';
} elseif (in_array($errorCode, self::RETRYABLE_ERRORS)) {
return 'retryable';
} elseif (in_array($errorCode, self::CONFIGURATION_ERRORS)) {
return 'configuration';
} elseif (in_array($errorCode, self::NETWORK_ERRORS)) {
return 'network';
} else {
return 'unknown';
}
}
private static function getRecommendedAction($category, $errorCode) {
switch ($category) {
case 'retryable':
return '实现重试机制,使用指数退避策略';
case 'configuration':
return '检查cURL选项配置和URL格式';
case 'network':
return '检查网络连接和DNS设置';
case 'unknown':
return '查看cURL文档了解错误代码 ' . $errorCode;
default:
return '无错误';
}
}
}
// 测试错误处理
$testUrls = [
"https://invalid-domain-12345.com", // 会触发CURLE_COULDNT_RESOLVE_HOST (6)
"https://httpbin.org/delay/10", // 如果超时设置短,会触发CURLE_OPERATION_TIMEDOUT (28)
"httpx://example.com" // 会触发CURLE_UNSUPPORTED_PROTOCOL (1)
];
foreach ($testUrls as $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 2 // 短超时以便测试
]);
curl_exec($ch);
$result = CurlErrorHandler::handleCurlError($ch, $url);
curl_close($ch);
echo str_repeat("-", 50) . "\n";
}
@endphp
@php
function makeCurlRequestWithSmartRetry($url, $options = []) {
$maxRetries = 3;
$retryDelay = 1;
$attempt = 0;
// 可重试的错误代码
$retryableErrors = [
CURLE_COULDNT_CONNECT, // 7
CURLE_OPERATION_TIMEDOUT, // 28
CURLE_GOT_NOTHING, // 52
CURLE_RECV_ERROR // 56
];
while ($attempt < $maxRetries) {
$attempt++;
echo "尝试第 {$attempt} 次请求...\n";
$ch = curl_init();
// 默认选项
$defaultOptions = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10
];
$finalOptions = $options + $defaultOptions;
curl_setopt_array($ch, $finalOptions);
$response = curl_exec($ch);
$errorCode = curl_errno($ch);
$errorMessage = curl_error($ch);
if ($errorCode === 0) {
echo "第 {$attempt} 次尝试成功!\n";
curl_close($ch);
return [
'success' => true,
'response' => $response,
'attempts' => $attempt,
'final_error' => null
];
}
echo "第 {$attempt} 次尝试失败 - 错误代码: {$errorCode}, 描述: {$errorMessage}\n";
// 检查是否应该重试
if (in_array($errorCode, $retryableErrors) && $attempt < $maxRetries) {
echo "错误代码 {$errorCode} 是可重试的,等待 {$retryDelay} 秒后重试...\n";
sleep($retryDelay);
$retryDelay *= 2; // 指数退避
} else {
echo "错误代码 {$errorCode} 不可重试或已达到最大重试次数\n";
break;
}
curl_close($ch);
}
return [
'success' => false,
'response' => null,
'attempts' => $attempt,
'final_error' => [
'code' => $errorCode,
'message' => $errorMessage
]
];
}
// 测试智能重试(使用一个可能超时的URL)
$result = makeCurlRequestWithSmartRetry("https://httpbin.org/delay/5");
if ($result['success']) {
echo "最终请求成功!经过 {$result['attempts']} 次尝试\n";
echo "响应数据长度: " . strlen($result['response']) . " 字节\n";
} else {
echo "所有尝试都失败了!\n";
echo "最后错误代码: " . $result['final_error']['code'] . "\n";
echo "最后错误描述: " . $result['final_error']['message'] . "\n";
echo "总共尝试了 {$result['attempts']} 次\n";
}
@endphp
@php
class CurlMonitor {
private static $errorStats = [];
public static function trackRequest($url, $ch) {
$errorCode = curl_errno($ch);
if ($errorCode !== 0) {
self::recordError($errorCode, $url);
// 检查是否需要触发报警
if (self::shouldTriggerAlert($errorCode)) {
self::triggerAlert($errorCode, $url);
}
}
return $errorCode;
}
private static function recordError($errorCode, $url) {
$timestamp = time();
$minute = date('Y-m-d H:i:00', $timestamp);
if (!isset(self::$errorStats[$minute])) {
self::$errorStats[$minute] = [];
}
if (!isset(self::$errorStats[$minute][$errorCode])) {
self::$errorStats[$minute][$errorCode] = [
'count' => 0,
'urls' => []
];
}
self::$errorStats[$minute][$errorCode]['count']++;
if (!in_array($url, self::$errorStats[$minute][$errorCode]['urls'])) {
self::$errorStats[$minute][$errorCode]['urls'][] = $url;
}
// 清理过期的统计数据(保留最近10分钟)
self::cleanupOldStats();
}
private static function shouldTriggerAlert($errorCode) {
$criticalErrors = [
CURLE_COULDNT_RESOLVE_HOST, // 6 - DNS问题
CURLE_SSL_CONNECT_ERROR // 35 - SSL问题
];
return in_array($errorCode, $criticalErrors);
}
private static function triggerAlert($errorCode, $url) {
$errorName = self::getErrorName($errorCode);
echo "[ALERT] 检测到关键错误!\n";
echo "错误代码: {$errorCode} ({$errorName})\n";
echo "发生URL: {$url}\n";
echo "时间: " . date('Y-m-d H:i:s') . "\n";
// 在实际应用中,这里可以发送邮件、短信或调用监控系统API
// mail('admin@example.com', 'cURL Critical Error', $alertMessage);
}
public static function getErrorStats() {
return self::$errorStats;
}
public static function getErrorName($errorCode) {
$errorNames = [
1 => 'CURLE_UNSUPPORTED_PROTOCOL',
6 => 'CURLE_COULDNT_RESOLVE_HOST',
7 => 'CURLE_COULDNT_CONNECT',
28 => 'CURLE_OPERATION_TIMEDOUT',
35 => 'CURLE_SSL_CONNECT_ERROR',
52 => 'CURLE_GOT_NOTHING'
];
return $errorNames[$errorCode] ?? 'UNKNOWN_ERROR';
}
private static function cleanupOldStats() {
$tenMinutesAgo = time() - 600;
$cutoffMinute = date('Y-m-d H:i:00', $tenMinutesAgo);
foreach (array_keys(self::$errorStats) as $minute) {
if ($minute < $cutoffMinute) {
unset(self::$errorStats[$minute]);
}
}
}
}
// 模拟多个请求并监控错误
$urls = [
"https://invalid-host-123.com",
"https://httpbin.org/status/500",
"https://valid-but-may-timeout.com"
];
foreach ($urls as $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3
]);
curl_exec($ch);
$errorCode = CurlMonitor::trackRequest($url, $ch);
if ($errorCode !== 0) {
$errorName = CurlMonitor::getErrorName($errorCode);
echo "请求失败: {$url} - 错误: {$errorCode} ({$errorName})\n";
} else {
echo "请求成功: {$url}\n";
}
curl_close($ch);
echo "---\n";
}
// 显示错误统计
echo "错误统计:\n";
print_r(CurlMonitor::getErrorStats());
@endphp
使用CURLE_*常量而不是硬编码数字,提高代码可读性。
根据错误代码将错误分类,实现不同的处理策略。
只为可重试的错误代码实现重试机制。