本文目录导读:

在PHP项目中处理超时请求,通常需要从应用层、服务器层和客户端层三个维度进行控制,以下是具体的实现方案:
脚本执行超时控制
使用 set_time_limit()
在脚本开头设置最大执行时间:
// 设置脚本最大执行时间为30秒 set_time_limit(30); // 或者动态调整 $timeout = 60; set_time_limit($timeout);
使用 register_shutdown_function() 捕获超时
register_shutdown_function(function() {
$error = error_get_last();
if ($error && $error['type'] === E_ERROR) {
// 处理超时错误
http_response_code(504);
echo json_encode(['error' => '请求超时']);
}
});
set_time_limit(5);
// 模拟耗时操作
sleep(10); // 这里会触发超时
HTTP请求超时控制
cURL 超时设置
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'http://example.com/api',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10, // 连接超时(秒)
CURLOPT_TIMEOUT => 30, // 总超时(秒)
CURLOPT_TIMEOUT_MS => 30000, // 毫秒级超时 (PHP 5.2.3+)
]);
$response = curl_exec($ch);
if (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT) {
// 处理超时
echo "请求超时";
}
curl_close($ch);
file_get_contents() 超时控制
$opts = [
'http' => [
'method' => 'GET',
'timeout' => 30, // 秒
]
];
$context = stream_context_create($opts);
$result = @file_get_contents('http://example.com', false, $context);
Guzzle HTTP 客户端超时
use GuzzleHttp\Client;
$client = new Client([
'timeout' => 30.0, // 响应超时
'connect_timeout' => 10.0, // 连接超时
'read_timeout' => 30.0, // 读取超时
'write_timeout' => 30.0, // 写入超时
]);
try {
$response = $client->get('http://example.com');
} catch (\GuzzleHttp\Exception\ConnectException $e) {
// 连接超时
} catch (\GuzzleHttp\Exception\RequestException $e) {
// 请求超时
}
数据库查询超时
MySQL 查询超时
// PDO
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$pdo->exec("SET SESSION MAX_EXECUTION_TIME = 5000"); // 毫秒
// mysqli
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$mysqli->query("SET SESSION MAX_EXECUTION_TIME = 5000");
Redis 操作超时
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 2.5); // 连接超时2.5秒
$redis->setOption(Redis::OPT_READ_TIMEOUT, 5); // 读取超时5秒
try {
$value = $redis->get('key');
} catch (RedisException $e) {
// 处理超时
}
服务器层面配置
Nginx 配置
# 在 server 或 location 块中配置
location ~ \.php$ {
fastcgi_read_timeout 300; # FastCGI 超时时间(秒)
fastcgi_connect_timeout 60; # 连接超时
fastcgi_send_timeout 300; # 发送超时
proxy_read_timeout 300; # 代理读取超时
}
Apache 配置
# httpd.conf 或 .htaccess
<IfModule mod_fcgid.c>
FcgidIOTimeout 300
FcgidBusyTimeout 300
FcgidConnectTimeout 60
</IfModule>
# PHP-FPM 配置
<IfModule mod_proxy_fcgi.c>
ProxyTimeout 300
</IfModule>
PHP-FPM 配置
; php-fpm.conf 或 pool.d/www.conf request_terminate_timeout = 300 ; 请求终止超时 request_slowlog_timeout = 30 ; 慢请求记录阈值 slowlog = /var/log/php-fpm/slow.log max_execution_time = 300 max_input_time = 300
超时处理最佳实践
队列处理长任务
// 使用消息队列处理耗时任务
class AsyncTaskProcessor {
public function handleLongTask($data) {
// 1. 将任务推入队列
$queue->push('process_task', $data);
// 2. 立即返回处理中状态
return ['status' => 'processing', 'task_id' => $taskId];
}
// 3. 后台 worker 处理实际逻辑
public function processTask($data) {
set_time_limit(0); // 无超时限制
// 执行耗时操作...
}
}
使用进程管理工具
// 使用 pcntl_fork 处理超时
$pid = pcntl_fork();
if ($pid == -1) {
die('Could not fork');
} elseif ($pid) {
// 父进程:设置超时计时器
$timeout = 30;
sleep($timeout);
// 如果子进程还在运行,发送终止信号
posix_kill($pid, SIGTERM);
pcntl_wait($status);
} else {
// 子进程:执行实际任务
set_time_limit(0);
// 执行耗时操作...
exit(0);
}
优雅的超时处理
class TimeoutHandler {
private $startTime;
private $timeout;
public function __construct($timeout = 30) {
$this->startTime = time();
$this->timeout = $timeout;
}
public function checkTimeout() {
if (time() - $this->startTime > $this->timeout) {
throw new TimeoutException('操作超时');
}
}
public function executeWithTimeout(callable $callback) {
while (true) {
$this->checkTimeout();
$result = $callback();
if ($result !== null) {
return $result;
}
usleep(100000); // 100ms
}
}
}
// 使用示例
$handler = new TimeoutHandler(10);
try {
$result = $handler->executeWithTimeout(function() {
// 执行需要超时控制的操作
return checkStatus();
});
} catch (TimeoutException $e) {
// 处理超时
echo $e->getMessage();
}
监控与告警
记录超时日志
class TimeoutLogger {
public static function log($context) {
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'url' => $_SERVER['REQUEST_URI'] ?? 'unknown',
'method' => $_SERVER['REQUEST_METHOD'] ?? 'unknown',
'timeout' => $context['timeout'],
'execution_time' => $context['execution_time']
];
error_log(json_encode($logData) . "\n", 3, '/var/log/php_timeout.log');
}
}
使用性能监控工具
- Xdebug:跟踪执行时间和内存使用
- Blackfire.io:性能分析
- New Relic:应用性能监控
常见问题及解决方案
| 问题 | 解决方案 |
|---|---|
| 文件上传超时 | 使用分片上传或异步处理 |
| 大量数据处理超时 | 使用分页或游标查询 |
| 第三方API响应慢 | 设置合理的超时时间,使用缓存 |
| 复杂计算超时 | 使用生成器或流式处理 |
推荐策略:对于新项目,建议使用队列系统(如RabbitMQ、Redis Queue)处理耗时操作,前端配合轮询或WebSocket获取结果,这比单纯增加超时时间更健壮。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播