本文目录导读:

在PHP项目中调用外部接口时,超时处理至关重要,能防止接口卡死导致整个请求阻塞,以下是几种常见方式的超时处理方案:
cURL 方式(最常用)
基础超时设置
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.example.com/endpoint");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 总超时时间(秒)
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 连接超时时间(秒)
$response = curl_exec($ch);
if (curl_errno($ch)) {
$error = curl_error($ch);
$errno = curl_errno($ch);
// 超时错误处理
if ($errno == CURLE_OPERATION_TIMEDOUT) {
echo "请求超时,请稍后重试";
// 记录日志
error_log("API 超时: " . $error);
}
}
curl_close($ch);
更精细的超时控制
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.example.com/endpoint");
// 毫秒级超时设置
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10000); // 10秒总超时(毫秒)
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 5000); // 5秒连接超时(毫秒)
// 设置重试次数
$maxRetries = 3;
$attempt = 0;
$response = false;
while ($attempt < $maxRetries && !$response) {
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch) != 0) {
$attempt++;
if ($attempt < $maxRetries) {
usleep(500000); // 等待0.5秒后重试
}
} else {
break;
}
}
file_get_contents 方式
$options = [
'http' => [
'method' => 'GET',
'timeout' => 10, // 超时时间(秒)
'ignore_errors' => true
],
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
]
];
$context = stream_context_create($options);
try {
$response = file_get_contents("https://api.example.com/endpoint", false, $context);
if ($response === false) {
throw new Exception("请求失败");
}
} catch (Exception $e) {
echo "接口调用超时或失败: " . $e->getMessage();
// 记录错误日志
}
Guzzle HTTP 客户端(推荐)
安装
composer require guzzlehttp/guzzle
使用示例
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ClientException;
$client = new Client([
'timeout' => 10, // 总超时
'connect_timeout' => 5, // 连接超时
'read_timeout' => 10, // 读取超时
'retry' => 3 // 重试次数
]);
try {
$response = $client->request('GET', 'https://api.example.com/endpoint', [
'headers' => [
'Authorization' => 'Bearer your_token'
]
]);
$body = $response->getBody();
$data = json_decode($body, true);
} catch (ConnectException $e) {
// 连接超时
echo "连接超时: " . $e->getMessage();
} catch (RequestException $e) {
// 请求超时或其他错误
if ($e->hasResponse()) {
$statusCode = $e->getResponse()->getStatusCode();
echo "请求失败,状态码: " . $statusCode;
} else {
echo "请求异常: " . $e->getMessage();
}
}
异步超时处理(Swoole/ReactPHP)
Swoole 协程方式
use Swoole\Coroutine\Http\Client;
use function Swoole\Coroutine\run;
run(function () {
$cli = new Client('api.example.com', 443, true);
$cli->set(['timeout' => 10]);
$cli->get('/endpoint');
if ($cli->statusCode === -1) {
echo "请求超时";
} else {
echo $cli->body;
}
$cli->close();
});
完整封装示例
class ApiClient
{
private $timeout = 10;
private $connectTimeout = 5;
private $maxRetries = 3;
public function request($method, $url, $data = [])
{
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
CURLOPT_CUSTOMREQUEST => strtoupper($method),
]);
if (!empty($data)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
}
$attempt = 0;
$response = null;
while ($attempt < $this->maxRetries) {
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
$errno = curl_errno($ch);
// 成功,跳出循环
if ($httpCode >= 200 && $httpCode < 300) {
break;
}
// 连接超时或请求超时,重试
if ($errno == CURLE_OPERATION_TIMEDOUT ||
$errno == CURLE_COULDNT_CONNECT) {
$attempt++;
if ($attempt < $this->maxRetries) {
$waitTime = pow(2, $attempt); // 指数退避
sleep($waitTime);
continue;
}
}
break;
}
curl_close($ch);
if ($response === false) {
throw new \Exception("API 请求失败: " . ($error ?? "未知错误"));
}
return json_decode($response, true);
}
}
// 使用示例
try {
$client = new ApiClient();
$result = $client->request('GET', 'https://api.example.com/data');
} catch (\Exception $e) {
echo "请求失败: " . $e->getMessage();
// 执行降级逻辑
}
最佳实践建议
超时时间设置
- 连接超时:3-5秒
- 读取超时:10-30秒(根据业务需求)
- 总超时:不超过30秒
错误处理策略
// 降级处理
function handleApiFailure($error)
{
// 1. 使用缓存数据
if ($cacheData = getFromCache('api_data')) {
return $cacheData;
}
// 2. 返回默认值
return ['status' => 'error', 'message' => '服务暂时不可用'];
// 3. 记录告警
sendAlert("API 服务异常: " . $error);
}
日志记录
function logApiCall($url, $response, $duration, $error = null)
{
$logData = [
'url' => $url,
'duration' => $duration,
'response_code' => $response['code'] ?? null,
'error' => $error,
'timestamp' => date('Y-m-d H:i:s')
];
// 写入日志文件
file_put_contents(
'/var/log/api_calls.log',
json_encode($logData) . PHP_EOL,
FILE_APPEND
);
}
监控告警
- 设置超时率告警阈值(如超过5%)
- 监控响应时间趋势
- 设置失败重试机制
- 实现熔断器模式
选择合适的超时方案取决于项目的具体情况,对于重要的生产环境,推荐使用 Guzzle 并配合完善的错误处理和重试机制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播