Yii2 REST控制器需继承yii\rest\Controller或ActiveController,配置JsonParser解析器并使用bodyParams加载数据,验证失败时自动返回JSON错误;通过response组件on beforeSend统一错误结构,确保Content-Type与Accept头协同。

Yii2 REST 控制器中表单验证失败时返回 JSON,关键不是“手动拼数组”,而是让整个验证流程自然落入框架的 JSON 响应链——从请求解析、验证触发、错误收集,到最终序列化输出,每一步都要对齐 REST 规范。
确保请求体能被正确解析为 PHP 数组
如果前端用 application/json 提交数据(如 {"username":"a","password":"123"}),但控制器里 $model->load(Yii::$app->request->post()) 始终为空,说明 JSON 解析器没启用:
- 在
config/web.php的components['request']中必须配置:'parsers' => ['application/json' => 'yii\web\JsonParser'] - 验证时改用
$model->load(Yii::$app->request->bodyParams, ''),因为 JSON 数据会自动注入bodyParams,而非post() - 不配解析器,
$model->validate()会因属性未赋值而“验证通过”,实际漏校验
让验证错误自动走 JSON 流程
继承 yii\rest\Controller 或 yii\rest\ActiveController 是前提。只有这类控制器才会在验证失败时自动触发 beforeAction → response->data = $model->errors → 经由 Serializer 序列化为 JSON:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 若用普通
yii\web\Controller,即使设了response->format = FORMAT_JSON,错误也不会自动转成{"username":["Username cannot be blank."]},得自己写if (!$model->validate()) { return $model->errors; } -
ActiveController的createAction和updateAction已内置验证失败返回逻辑,无需重写 - 自定义动作中,统一用
if (!$model->validate()) { return $model->errors; }即可,框架会将其作为response->data正常 JSON 化
统一错误结构(含验证错误)
默认返回的 $model->errors 是扁平数组,如 {"username":["..."]},但业务常需包一层 {"code":400,"message":"Validation failed","errors":{...}}。推荐在 config/web.php 的 response 组件中用 on beforeSend 拦截:
- 只处理
FORMAT_JSON且is_array($response->data)的响应,避免干扰文件下载等场景 - 判断
$response->statusCode >= 400时,将原$response->data移入errors字段,同时补code和message - 这样无论是模型验证失败(422)、路由不存在(404)还是权限不足(403),都保持同一壳结构
注意 Content-Type 与 Accept 头协同
浏览器直接访问 POST 接口或 Postman 未设头时,可能返回 HTML 错误页,而非 JSON:
- 测试务必带上
-H "Accept: application/json",否则ContentNegotiator可能 fallback 到 HTML - 内部系统可强制协商:在控制器
behaviors()中覆盖contentNegotiator,添加'text/html' => Response::FORMAT_JSON - 但不要删掉
'application/json' => Response::FORMAT_JSON,否则标准 API 客户端会失效

















