Yii2 API场景下需将表单验证错误转为JSON响应:显式调用validate(),失败时用422状态码返回扁平化errors(取各字段首个错误),可封装formatErrors()处理,并在控制器统一拦截输出。

Yii2 表单验证失败时,默认返回的是 HTML 页面或重定向,但在前后端分离或 API 场景下,需要将验证错误以 JSON 格式统一返回,便于前端解析展示。核心思路是捕获 Model::validate() 的结果,将 $model->errors 结构转换为扁平、语义清晰的 JSON 响应。
统一拦截验证失败并转为 JSON
在控制器中,不直接调用 $model->save()(它会自动 validate),而是显式验证,并手动控制响应格式:
- 调用
$model->validate()触发规则校验 - 检查
$model->hasErrors()判断是否出错 - 若出错,用
yii\helpers\Json::encode()将错误结构标准化输出,并设置 HTTP 状态码为 422(Unprocessable Entity)
示例代码:
public function actionCreate()
{
$model = new Post();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if ($model->save()) {
return $this->asJson(['success' => true, 'data' => $model->attributes]);
}
}
// 验证失败:返回结构化错误
if ($model->hasErrors()) {
Yii::$app->response->setStatusCode(422);
return $this->asJson([
'success' => false,
'errors' => $this->formatErrors($model->errors)
]);
}
}
规范错误字段结构(key → message)
Yii2 默认的 $model->errors 是二维数组:['title' => ['标题不能为空', '标题长度不能超过20']]。前端通常更希望是扁平 key-value 形式,例如:{"title": "标题不能为空"}(取每字段首个错误)。可封装一个辅助方法:
- 遍历
$errors,对每个属性取$errors[$attribute][0] - 支持自定义 message 拼接(如加前缀“请填写”)
- 避免空字段或 null 错误干扰
参考 formatErrors() 实现:
protected function formatErrors($errors)
{
$result = [];
foreach ($errors as $attribute => $msgs) {
if (!empty($msgs)) {
$result[$attribute] = is_array($msgs) ? reset($msgs) : $msgs;
}
}
return $result;
}
全局处理(适用于 RESTful 应用)
若项目大量使用 API,可在 behaviors() 中配置 ContentNegotiator 和自定义 beforeAction 统一拦截验证异常:
- 重写
beforeAction(),在ActiveForm或模型 save 失败时提前终止流程 - 监听
yii\base\ModelEvent::EVENT_BEFORE_VALIDATE不推荐;更稳妥的是在控制器层统一出口处理 - 配合
yii\rest\Controller时,可继承并覆盖afterAction()对验证失败做响应修正
前端接收与提示建议
返回的 JSON 示例:
{
"success": false,
"errors": {
"title": "标题不能为空",
"content": "内容必须至少10个字符"
}
}
前端可直接遍历 response.errors,按字段 ID 插入对应 <span class="error"></span> 提示,无需解析嵌套结构。注意保留原始字段名(如 user[username] 这类复合名需在模型中用 formName() 或自定义场景处理)。


















