本文目录导读:

在PHP项目中处理请求超时异常,可以从以下几个层面进行:
PHP脚本执行时间限制
设置执行时间
// 设置无限制执行时间(不安全) set_time_limit(0); // 设置具体秒数 set_time_limit(300); // 5分钟 // 也可以在php.ini中设置 ; max_execution_time = 300
捕获超时异常
try {
// 某些耗时操作
$result = someTimeConsumingOperation();
} catch (Exception $e) {
if (strpos($e->getMessage(), 'Maximum execution time') !== false) {
// 处理超时异常
error_log('Script execution timed out: ' . $e->getMessage());
http_response_code(503);
echo json_encode(['error' => '请求超时,请稍后重试']);
} else {
throw $e; // 重新抛出其他异常
}
}
数据库查询超时
MySQL查询超时
// 设置MySQL查询超时(5秒)
$pdo = new PDO($dsn, $user, $pass);
$pdo->exec("SET SESSION max_execution_time = 5000");
// 或使用PDO Statement超时
$stmt = $pdo->prepare("SELECT * FROM large_table");
$stmt->execute();
Redis操作超时
$redis = new Redis();
try {
$redis->connect('127.0.0.1', 6379, 2.5); // 2.5秒连接超时
$redis->setOption(Redis::OPT_READ_TIMEOUT, 5); // 5秒读取超时
$result = $redis->get('some_key');
} catch (RedisException $e) {
error_log('Redis timeout: ' . $e->getMessage());
// 降级处理
}
cURL请求超时
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.example.com',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10, // 连接超时10秒
CURLOPT_TIMEOUT => 30, // 总超时30秒
CURLOPT_TIMEOUT_MS => 30000, // 毫秒单位
]);
$response = curl_exec($ch);
if (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT) {
error_log('cURL request timed out');
echo "请求超时,请稍后重试";
}
curl_close($ch);
HTTP请求超时(使用Guzzle)
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\TransferException;
$client = new Client([
'timeout' => 10, // 总超时
'connect_timeout' => 5, // 连接超时
'read_timeout' => 30, // 读取超时
]);
try {
$response = $client->get('https://api.example.com/data');
} catch (ConnectException $e) {
error_log('Connection timeout: ' . $e->getMessage());
} catch (TransferException $e) {
error_log('Transfer timeout: ' . $e->getMessage());
}
进程管理方案
使用pcntl实现超时控制
declare(ticks = 1);
// 设置超时信号
function timeout_handler($signo) {
throw new \RuntimeException('Process timeout', 408);
}
pcntl_signal(SIGALRM, 'timeout_handler');
pcntl_alarm(30); // 30秒超时
try {
// 耗时操作
longRunningProcess();
pcntl_alarm(0); // 取消闹钟
} catch (\RuntimeException $e) {
if ($e->getCode() == 408) {
error_log('Process timed out');
// 降级处理
}
}
异步处理和队列方案
使用消息队列处理长任务
// 1. 提交任务到队列
$jobId = $queue->push(new LongRunningJob($data));
// 2. 返回立即响应
echo json_encode([
'status' => 'accepted',
'job_id' => $jobId,
'message' => '任务已提交,稍后查看结果'
]);
// 3. 后台Worker处理
class LongRunningJob
{
public function handle()
{
try {
set_time_limit(600); // 允许10分钟
// 处理任务...
} catch (\Exception $e) {
Log::error('Job timeout: ' . $e->getMessage());
// 重试或记录失败
}
}
}
全局超时中间件(框架示例)
Laravel/Symfony中间件
namespace App\Http\Middleware;
use Closure;
use Symfony\Component\HttpKernel\Exception\HttpException;
class RequestTimeout
{
public function handle($request, Closure $next, $timeout = 30)
{
// 设置最大执行时间
set_time_limit($timeout);
try {
$response = $next($request);
} catch (\Exception $e) {
if (strpos($e->getMessage(), 'Maximum execution time') !== false) {
throw new HttpException(504, 'Request timeout');
}
throw $e;
}
return $response;
}
}
最佳实践建议
分层超时设置
class TimeoutHandler
{
const DEFAULT_TIMEOUT = 30;
const DB_TIMEOUT = 5;
const API_TIMEOUT = 10;
const FILE_TIMEOUT = 60;
public static function handle(callable $callback, $timeout = self::DEFAULT_TIMEOUT)
{
$startTime = microtime(true);
try {
$result = $callback();
$elapsed = microtime(true) - $startTime;
if ($elapsed > $timeout) {
throw new TimeoutException("Operation exceeded {$timeout}s");
}
return $result;
} catch (TimeoutException $e) {
// 记录慢查询
Log::warning('Slow operation detected', [
'timeout' => $timeout,
'elapsed' => $elapsed ?? 0
]);
// 返回降级数据
return self::getFallbackData();
}
}
private static function getFallbackData()
{
return ['error' => '请求超时', 'status' => 'timeout'];
}
}
// 使用
$result = TimeoutHandler::handle(function() {
return $api->getData();
}, TimeoutHandler::API_TIMEOUT);
超时监控和告警
// 记录超时事件用于监控
$timeoutMetrics = [
'timestamp' => time(),
'endpoint' => $_SERVER['REQUEST_URI'],
'method' => $_SERVER['REQUEST_METHOD'],
'timeout_seconds' => $timeout,
];
// 发送到监控系统
Metrics::increment('request.timeout', $timeoutMetrics);
总结建议
- 区分超时类型:连接超时、响应超时、执行超时等
- 设置合理超时:根据业务场景调整(API调用5-10s,文件处理30-60s)
- 优雅降级:超时时返回友好的错误信息或缓存数据
- 异步处理:长任务使用消息队列异步执行
- 监控告警:记录超时事件并设置告警
- 前端配合:前端设置合理的AJAX超时并显示加载状态
- 避免无限等待:所有外部调用必须设置超时
选择哪种方案取决于你的具体业务需求和系统架构,如果问题依然存在,建议排查慢查询、网络延迟、资源竞争等根本原因。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播