yii2 json接口验证不生效的四大原因:一、数据未正确加载进模型,需手动解析json并调用load($data, '');二、rules()格式错误或验证方法非public;三、场景未在scenarios()中声明且未显式赋值;四、响应未设为json格式或被提前输出中断。

Yii2 表单验证在 JSON 接口场景下“不生效”,通常不是规则写错了,而是验证根本没跑起来——validate() 静默返回 true,脏数据直接入库。核心问题出在四个环节没对齐:模型属性、规则定义、场景激活、数据加载。下面按实际排查顺序列关键点。
一、数据压根没进模型(最常见)
验证前必须让数据进模型,否则 validate() 没东西可验。
- 控制器里不能只写
$model->validate(),必须先调$model->load($request->post())或$model->load($data, '') - 前端发的是
{"username":"a"},但模型默认期望loginform[username]这种带前缀的键名——这时 load 第二个参数要传空字符串:$model->load($data, '') - JSON 请求必须手动解析:
$raw = $request->getRawBody(); $data = \yii\helpers\Json::decode($raw); $model->load($data, '')。不这么做,load()返回 false,但你不检查就直接validate(),结果永远“通过”
二、rules() 写法或位置不对
规则必须严格按格式写在模型的 rules() 方法里,错一个括号、少一层数组,就静默失效。
-
rules()必须返回二维数组,每条规则是[['attr1', 'attr2'], 'validator', 'param' => 'value']形式 - 错误写法:
['username', 'required'](少了一层中括号),会被当成单个字符串忽略 - 别用
errorMessage,Yii2+ 统一用message - 自定义验证方法必须是
public,签名只能是function($attribute, $params),多一个参数或 private 都会跳过
三、场景(scenario)设了但没起效
写了 'on' => ['create'] 却没生效?三个地方必须同时到位:
- 模型类中重写
scenarios(),显式返回字段白名单,例如:return ['create' => ['name', 'email']];不写这个,字段连加载都进不去 -
rules()里每条带on的规则,场景名必须和scenarios()中定义的一致 - 控制器中必须在
load()后、validate()前写:$model->scenario = 'create';构造时传参或配置里设都不管用
四、JSON 响应头或格式干扰验证判断
验证失败后返回 JSON,但前端收不到错误信息?问题可能不在验证本身,而在响应输出环节。
- 确保控制器 action 开头就设:
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;,否则返回的是 HTML 包裹的字符串 - 验证失败时别只写
if (!$model->validate()) { return ['error' => $model->errors]; },要先设 format,再 return 数组 - 检查 Network 面板 Response Headers 是否含
Content-Type: application/json; charset=UTF-8,缺失会导致前端解析中断 - 别在 action 里提前
echo、var_dump或exit,否则 response 格式设置失效











