Yii2 REST接口自定义参数验证核心是在控制器或动作中主动校验请求数据,而非仅依赖模型规则;支持手动校验、Model结构化验证、场景级条件验证及全局拦截四种方式。

Yii2 REST 接口中自定义参数验证,核心是**在控制器或动作中对请求数据做主动校验**,而不是只依赖模型规则(Model Rules)。因为 REST 接口常接收 JSON 请求体(如 POST /api/users),参数可能不在表单字段中,或需跨字段、动态、业务逻辑级校验。
1. 在控制器动作中手动验证请求参数
适用于简单、轻量、非模型绑定的校验(比如必须传某个 header、参数格式特殊、权限前置检查等):
- 用
$request = Yii::$app->request获取参数(get()、post()、getBodyParams()、getHeaders()) - 手动判断并抛出
BadRequestHttpException或自定义异常
示例:校验 JSON body 中必须有 category 且为字符串:
public function actionCreate()
{
$body = Yii::$app->request->getBodyParams();
if (!isset($body['category']) || !is_string($body['category'])) {
throw new BadRequestHttpException('Missing or invalid "category" field.');
}
// 继续处理...
}2. 使用 Model 进行结构化验证(推荐)
把请求数据封装进一个继承 yii\base\Model 的验证类(不一定要关联数据库),复用 Yii2 验证器体系:
- 定义验证类(如
forms/CreateUserForm.php),声明public $name; public $email;等属性 - 在
rules()中写标准规则(required、email、string)和自定义规则(validatePassword) - 在控制器中加载数据并调用
$model->load($data, '') && $model->validate()
示例:自定义密码强度校验:
public function rules()
{
return [
[['name', 'email'], 'required'],
['email', 'email'],
['password', 'validatePassword'],
];
}
<p>public function validatePassword($attribute, $params)
{
if (strlen($this->password) addError($attribute, 'Password must be at least 8 characters.');
}
}</p>3. 使用场景级验证器(如条件验证、跨字段)
当校验逻辑依赖其他字段或上下文时,用 when 或自定义方法更灵活:
-
'when' => function ($model) { return $model->type === 'premium'; }控制规则触发条件 - 用
filter规则预处理参数(如 trim、intval) - 在
beforeValidate()中动态添加规则或修改属性值
例如:仅当 status 为 active 时才要求 start_date:
['start_date', 'required', 'when' => function ($model) {
return $model->status === 'active';
}]4. 全局或动作级参数拦截(如 via actions() 或 behaviors)
适合通用校验(如 API token、版本头、签名验证),避免每个 action 重复写:
- 在控制器中重写
behaviors(),添加AuthBehavior或自定义BaseApiFilter - 使用
beforeAction()统一提取/校验参数,失败直接return false - 配合
ActionFilter实现可复用的参数校验组件(如校验 timestamp + sign)
示例(beforeAction 检查时间戳防重放):
public function beforeAction($action)
{
$ts = Yii::$app->request->getHeaders()->get('X-Timestamp');
if (!$ts || abs(time() - (int)$ts) > 300) {
throw new UnauthorizedHttpException('Invalid or expired timestamp.');
}
return parent::beforeAction($action);
}











