yii2 api错误响应不统一的根本原因是errorhandler仅在yii_debug=false且请求含accept:application/json或为ajax时才返回json,而多数客户端(如curl、postman、小程序)不发该头,导致返回html白屏;应于web/index.php中run()前监听event_before_request,依据getcontenttype()或isajax强制设response->format为format_json,并在actionerror中手动设置statuscode以确保状态码正确。

Yii2后端API报错不统一,本质是默认的 yii\web\ErrorHandler 没被正确接管——它只在特定条件下(如 YII_DEBUG = false 且请求带 Accept: application/json)才返回 JSON,而绝大多数 API 客户端(curl、Postman 默认、小程序、App)根本不会发这个 header,结果你看到的是 HTML 白屏、500 响应体里混着 标签,或者干脆空响应。
怎么让所有异常强制走 JSON 流程
不能依赖客户端 header,得在请求生命周期早期就“锁死”响应格式。最稳妥的位置是在 web/index.php 中 (new yii\web\Application($config))->run(); 之前插入:
Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
// 只要内容类型是 JSON 或是 AJAX 请求,就强制设为 JSON 格式
if (strpos(Yii::$app->request->getContentType(), 'application/json') !== false || Yii::$app->request->isAjax) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
}
});
注意:getContentType() 比检查 Accept 头更可靠,因为小程序、App 等常只发 Content-Type: application/json 而不带 Accept;isAjax 是兜底项,对 jQuery 类请求有效。
- 别把这段逻辑放在
bootstrap阶段——Yii::$app->request此时尚未初始化 - 如果项目有前后端分离的 Web 页面(非 API),这段代码会误伤它们的错误页,此时应改用模块级配置:为 API 模块单独定义
errorHandler组件 -
FORMAT_JSON只影响正常响应体,对错误流无效——但它能让后续actionError返回的数组自动序列化成 JSON,且状态码不被重置为 200
为什么 actionError 里 return 数组还是返回 200 状态码
因为 Yii 默认把 actionError 当作普通 action 处理,不自动继承异常的 HTTP 状态码。即使你抛出的是 NotFoundHttpException,actionError 里不手动设 statusCode,响应就是 200。
正确写法(以 controllers/ApiController.php 为例):
public function actionError()
{
$exception = Yii::$app->errorHandler->exception;
if ($exception !== null) {
// 关键:手动设 statusCode,否则永远是 200
Yii::$app->response->statusCode = $exception->statusCode ?: 500;
return [
'code' => $exception->getCode() ?: 50000,
'message' => $exception->getMessage(),
'data' => [],
];
}
}
-
$exception->statusCode对HttpException子类(如BadRequestHttpException)有效,对普通Exception是null,必须兜底设500 - 不要在
actionError里再throw新异常,否则触发二次错误处理,可能死循环 - 返回数组即可,Yii 会自动调用
JsonResponseFormatter,别echo json_encode()或die()
如何让自定义业务异常也进 error handler
直接 throw new Exception('xxx') 会绕过 Yii 的 ErrorHandler,PHP 直接吐致命错误页面(HTML)。必须让所有异常都走框架流程。
- 客户端错误优先用
throw new \yii\web\BadRequestHttpException('xxx'),它自带400状态码 - 业务逻辑错误应继承
\yii\base\UserException(不是Exception),它是 Yii 认可的“用户可控异常”,会被ErrorHandler捕获且不记录为严重错误 - 绝对避免在控制器或模型里用
die()、exit()、var_dump()+die(),这些会中断框架生命周期 - 检查
config/web.php是否误删了'errorHandler'组件配置——哪怕只留空数组也会启用默认 handler
API 模块里 errorAction 配置容易漏掉的关键点
如果你把 API 单独做成模块(比如 modules/v1/Module.php),光在主应用配置 errorAction 不生效,模块会用自己的 errorHandler 实例。
必须在模块配置中显式覆盖:
public function init()
{
parent::init();
Yii::$app->set('errorHandler', [
'class' => 'yii\web\ErrorHandler',
'errorAction' => 'v1/error', // 注意路径是模块内路由
]);
}
同时确保该模块下有 controllers/ErrorController.php 并含 actionError() 方法。否则请求一出错就 fallback 到主应用的 site/error,而它大概率返回 HTML。
最易忽略的是:模块的 errorAction 路由必须能被访问到——检查是否被 AccessControl 或 AuthManager 拦截(error 动作应允许游客访问)。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











