本文目录导读:

在PHP项目中处理接口超时,需要从客户端发起请求和服务端处理请求两个层面分别设置,以下是详细的配置和处理方案:
客户端请求超时设置(发起HTTP请求时)
cURL 方式
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://api.example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 总超时时间10秒
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 连接超时5秒
// 高级设置:传输速度限制
curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, 1024); // 1024字节/秒
curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, 10); // 持续10秒低于限速则超时
$response = curl_exec($ch);
if (curl_errno($ch)) {
$error = curl_error($ch);
// 处理超时错误
if (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT) {
echo "请求超时";
}
}
curl_close($ch);
Guzzle HTTP 客户端
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
$client = new Client([
'timeout' => 10, // 总超时
'connect_timeout' => 5, // 连接超时
'read_timeout' => 8, // 读取超时
]);
try {
$response = $client->get('http://api.example.com', [
'timeout' => 10,
'connect_timeout' => 5
]);
} catch (RequestException $e) {
if ($e->hasResponse()) {
$statusCode = $e->getResponse()->getStatusCode();
}
// 处理超时
if ($e instanceof ConnectException) {
echo "连接超时";
}
if ($e->getCode() == CURLE_OPERATION_TIMEDOUT) {
echo "请求超时";
}
}
file_get_contents 方式
<?php
$ctx = stream_context_create([
'http' => [
'timeout' => 10, // 超时时间(秒)
'method' => 'GET'
]
]);
$result = @file_get_contents('http://api.example.com', false, $ctx);
if ($result === false) {
echo "请求失败或超时";
}
服务端处理超时设置(PHP脚本执行)
set_time_limit() 函数
<?php // 设置脚本最大执行时间 set_time_limit(30); // 30秒 // 设置为0表示无限制(不推荐生产环境) // set_time_limit(0); // 处理耗时操作 processLongTask();
max_execution_time 配置(php.ini)
; 修改 php.ini 文件 max_execution_time = 30 ; 或者针对特定虚拟机 max_input_time = 60
使用 pcntl 实现更精确的控制
<?php
declare(ticks = 1);
// 超时回调函数
function timeout_handler($signo) {
throw new Exception('脚本执行超时');
}
// 设置超时信号
pcntl_signal(SIGALRM, 'timeout_handler');
pcntl_alarm(10); // 10秒后触发
try {
// 执行可能超时的操作
while (true) {
// 处理数据
}
} catch (Exception $e) {
echo "脚本执行超时: " . $e->getMessage();
} finally {
pcntl_alarm(0); // 取消闹钟
}
数据库查询超时设置
<?php
// MySQL 示例
try {
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 5); // 设置连接超时
// 执行超时查询
$stmt = $pdo->prepare('SELECT SLEEP(20)');
// MySQL 查询超时
$pdo->exec("SET SESSION MAX_EXECUTION_TIME = 1000"); // 1秒(MySQL 5.7+)
$stmt->execute();
} catch (PDOException $e) {
echo "数据库操作超时: " . $e->getMessage();
}
综合处理方案(推荐)
使用重试机制
<?php
function requestWithRetry($url, $maxRetries = 3, $timeout = 10) {
$retries = 0;
$success = false;
$result = null;
while (!$success && $retries < $maxRetries) {
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT) {
$retries++;
// 指数退避策略
$waitTime = pow(2, $retries);
sleep($waitTime);
continue;
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode >= 200 && $httpCode < 300) {
$success = true;
}
curl_close($ch);
} catch (Exception $e) {
$retries++;
if ($retries >= $maxRetries) {
throw $e;
}
}
}
return $result;
}
使用消息队列处理
<?php
// 使用 Redis 或 RabbitMQ 实现异步处理
// 接口立即返回,后台异步处理
public function handleAsyncRequest() {
$jobData = ['type' => 'process', 'data' => $input];
// 推送到消息队列
Redis::lpush('queue:processing', json_encode($jobData));
return ['status' => 'accepted', 'message' => '请求已接收'];
}
最佳实践建议
-
分层设置超时:
- 客户端超时 < 服务端超时 < 负载均衡器超时
- 客户端10秒 < PHP 30秒 < Nginx 60秒
-
使用监控和报警:
// 记录超时日志 function logTimeout($service, $timeout) { $log = [ 'time' => date('Y-m-d H:i:s'), 'service' => $service, 'timeout' => $timeout, 'url' => $_SERVER['REQUEST_URI'] ?? '' ]; file_put_contents('/var/log/timeout.log', json_encode($log) . PHP_EOL, FILE_APPEND); } -
超时阈值设置建议:
- 普通API:5-10秒
- 文件上传:30-60秒
- 批量处理:根据数据量动态设置
- 长连接/推送:使用 WebSocket 或 SSE
-
性能优化:
// 使用异步非阻塞方式 // Swoole 或 ReactPHP 实现协程处理 go(function () { $result = Co::exec("curl -s http://api.example.com", 5); });
选择合适的超时处理方案需要根据具体的业务场景、系统架构和性能要求来决定,对于关键业务,建议同时使用多种策略组合(超时+重试+降级)。