必须替换 yii2 默认 errorhandler 的 renderexception 行为,在 components 中配置自定义 erroraction 并在 actionerror 中统一返回 json 格式 {“code”:xxx, “message”:”xxx”},同时映射 http 状态码到业务码、截取堆栈、记录日志。

Yii2 API 错误响应被截断或格式混乱
默认情况下,Yii2 的 yii\web\ErrorHandler 会把异常渲染成 HTML 页面——这对 API 来说完全不可用。你看到的可能是空响应、500 页面源码、或者 JSON 里混着 HTML 标签。
- 必须禁用 HTML 渲染:在
config/web.php中确保'errorHandler' => ['errorAction' => 'site/error']被移除或重定向到纯 JSON action - 更稳妥的做法是直接关闭
yii\web\ErrorHandler对 API 请求的接管:在bootstrap阶段或beforeAction中判断Yii::$app->request->getIsAjax() || Yii::$app->request->getIsJson(),手动 throwHttpException并由自定义响应处理器捕获 - 别依赖
responseFormat = Response::FORMAT_JSON全局设置——它只影响正常返回,不接管错误流
如何让所有异常统一输出为 {“code”:xxx, “message”:”xxx”}
核心不是改 view,而是替换 yii\web\ErrorHandler 的 renderException() 行为。最轻量的方式是在 components 里注册自定义 error handler:
'errorHandler' => [
'class' => 'yii\web\ErrorHandler',
'errorAction' => 'api/error',
],
然后在 controllers/ApiController.php 里写一个 actionError():
public function actionError()
{
$exception = Yii::$app->errorHandler->exception;
if ($exception !== null) {
Yii::$app->response->statusCode = $exception->statusCode ?: 500;
return [
'code' => $exception->getCode() ?: 50000,
'message' => $exception->getMessage(),
'data' => [],
];
}
}
- 注意:这个 action 必须返回数组(Yii2 会自动 JSON 化),不能 echo 或 die
-
$exception->statusCode对HttpException有效,但对Exception是 null,得兜底 - 别在
actionError里再 throw 异常,否则二次进入 error handler,可能死循环
400/401/403/404 这些状态码怎么精准映射到自定义字段
靠人工 if-else 判断 $exception instanceof 太脆弱。推荐用 yii\web\HttpException 子类 + 自定义 code 映射表:
// 在 actionError 里
$codeMap = [
400 => 10001,
401 => 10002,
403 => 10003,
404 => 10004,
500 => 50000,
];
$statusCode = $exception->statusCode ?: 500;
$apiCode = $codeMap[$statusCode] ?? 50000;
- 401 和 403 容易混淆:认证失败(token 过期)用 401,权限不足(有 token 但没权限)用 403
- 不要把数据库唯一约束失败硬塞进 400 —— 更合适的是捕获
IntegrityConstraintViolationException,转成 400 + code=20001 - Yii2 默认的
NotFoundHttpException是 404,但前端可能需要区分“资源不存在”和“接口不存在”,这时得自定义子类
调试时看不到真实错误堆栈,只看到“Internal Server Error”
生产环境关闭 YII_DEBUG 后,yii\web\ErrorHandler 会隐藏堆栈信息。但 API 调试阶段需要它,又不能暴露给前端。
- 加个开关逻辑:检查请求头
Authorization或 IP 白名单,白名单内才返回trace字段 - 别把
$exception->getTraceAsString()直接塞进响应——太长且含敏感路径,用array_slice($exception->getTrace(), 0, 5)截取前 5 层即可 - 日志必须记全量:
Yii::error($exception, 'api'),否则线上出问题根本没法回溯
真正麻烦的不是格式统一,而是异常源头分散:验证规则抛的、DB 层抛的、第三方 SDK 抛的……每个都得有对应转换逻辑,漏一个,API 就崩一次静默错误。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










