Yii2超时错误不会自动触发错误提示机制,因cURL等底层超时常返回false或抛特定异常(如RequestException),而errorHandler仅捕获未处理异常;需显式配置timeout、单独catch RequestException,并用addError()或JSON响应返回友好提示。

Yii2 网络超时报错(比如 cURL 超时、file_get_contents 超时、HTTP 客户端请求卡死)本身不会自动触发 Yii 的错误提示机制——它通常表现为 PHP 抛出 Exception 或返回 false,但若没被显式捕获,就可能静默失败或变成 500 错误页,用户完全看不到“超时”这个关键信息。
为什么 try/catch 捕获不到超时提示?
常见误区是以为只要写了 try/catch 就能统一显示友好提示,但实际中:
- 部分 HTTP 客户端(如老版本
yii\httpclient\Client)在超时后抛的是yii\httpclient\Exception,而有些底层封装(如直接用curl_exec)可能只返回false,不抛异常 - Yii 的
errorHandler默认只接管未捕获的异常,对return false或if (!$response)这类逻辑分支无感知 - 即使捕获了异常,若没调用
$this->addError()或Yii::$app->session->setFlash(),前端根本不会渲染任何提示
yii\httpclient\Client 超时必须显式配置 timeout 和捕获 RequestException
Yii2 自带 HTTP 客户端默认不设超时,底层依赖 cURL 时会使用 PHP 默认的无限等待,极易卡住。必须主动设限并处理异常类型:
- 配置
timeout:在创建 client 时传入,单位秒,例如['timeout' => 5];注意这不是连接超时(connectTimeout),两者要分开设 - 捕获具体异常类:超时抛的是
yii\httpclient\RequestException(不是通用\Exception),需单独catch - 避免用
Yii::$app->errorHandler->exception($e)渲染——它会强制跳转到 error 页面,不适合局部 AJAX 请求
示例:
$client = new \yii\httpclient\Client(['timeout' => 5, 'connectTimeout' => 3]);
try {
$response = $client->get('https://api.example.com/data')->send();
} catch (\yii\httpclient\RequestException $e) {
$this->addError('server', '请求超时,请稍后重试');
// 或写 session 提示:Yii::$app->session->setFlash('error', '服务暂时不可用');
}
模型层验证失败时用 $this->addError() 才能进 ActiveForm 自动提示
如果超时发生在模型的 beforeValidate() 或自定义验证逻辑里,且你想让错误和必填、格式错误一样显示在表单下方,就必须走 Yii 的验证流程:
- 不能只写
Yii::$app->session->setFlash()—— 它只存 session,不绑定字段,ActiveForm不会自动显示 - 必须调用
$this->addError('attribute_name', '提示文案'),attribute 名要和表单字段一致 - 若超时影响的是整个操作而非单个字段(比如提交前校验第三方服务连通性),可用伪属性名如
'_network',并在视图中用$form->error($model, '_network')单独渲染
API 接口超时要返回 JSON 结构,别依赖 HTML 错误页
对 Accept: application/json 请求,超时错误绝不能返回 Yii 默认的 HTML 错误页(否则前端解析失败,看到一堆 <div>)。关键点:
<ul>
<li>在 <code>actionError 里判断请求类型:if (Yii::$app->request->getIsJson()) { ... }
catch 块里直接 throw new HttpException(504) —— 这会再次进 ErrorHandler,而默认 renderException 仍输出 HTMLcatch 后手动构造数组返回,例如 return ['code' => 504, 'message' => '网关超时'];,并确保控制器行为已设 Yii::$app->response->format = Response::FORMAT_JSON;
容易被忽略的是:PHP 层面的超时(如 set_time_limit(0) 被禁用)或 FPM 的 request_terminate_timeout 触发时,PHP 进程会被强制 kill,此时连 catch 都无法执行——这种真超时只能靠 Nginx/ALB 的上游超时配置 + 前端重试兜底。


















