【问题标题】:How to validate params comming from GET request in Yii2 RESTful service如何验证来自 Yii2 RESTful 服务中的 GET 请求的参数
【发布时间】:2016-04-15 10:34:00
【问题描述】:

我有一个language 参数需要发送到我的文档端点。所以我必须验证用户是否在他的 GET 请求中发送了这个参数。

在我的模型中制定规则没有做任何事情:

public function rules()
{
    return [
        [['language'], 'required'],
    ];
}

因为我已经尝试过这个:

1) 我已经创建了 ParamsValidator 类:

<?php
namespace app\modules\v1\components;

use yii\web\UnprocessableEntityHttpException;
use yii\base\Component;
use Yii;

/**
 * Class that is responsible for validating input params.
 */
class ParamsValidator extends Component
{
    public function validate($params)
    {
        if (!isset($params['language'])) {
            throw new UnprocessableEntityHttpException("Language parameter is required");
        }
    }
}

我在我的控制器init() 方法中调用它的validate() 方法:

public function init()
{
    $this->_params = Yii::$app->request->queryParams;

    $validator = new ParamsValidator();
    $validator->validate($this->_params);
}

还有这种工作。代码有效,但我得到了丑陋的回应。我得到的不是很好的 JSON 响应,而是像这样开始的一堆 html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Unprocessable entity (#422)</title>
        <style>
        body {
            font: normal 9pt "Verdana";
            color: #000;
            background: #fff;
        }

我想要一些不错的 JSON 响应,而不是这个 html:

{
    "name": "Forbidden",
    "message": "You are not authorized to do this.",
    "code": 0,
    "status": 403,
    "type": "yii\\web\\ForbiddenHttpException"
}

您看到的这个漂亮的 JSON 错误是由:

$behaviors['authenticator'] = [
    'class' => HttpBasicAuth::className(),
    'auth' => [$this, 'authenticate']
];

但显然我的验证器没有这样做。

问题:

1) 如何验证来自 GET 请求的参数?
2) 如果我的方法是正确的,如何得到这个漂亮的 JSON 错误响应?

【问题讨论】:

    标签: json rest validation get yii2


    【解决方案1】:

    一个简单的选择是通过在控制器内部添加这个来覆盖ActiveController::checkAccess 方法:

    public function checkAccess($action, $model = null, $params = [])
    {
        if ($action === 'index' or $action === 'view') 
        {
            $params = Yii::$app->request->queryParams;
            if (!isset($params['language'])) {
                 throw new \yii\web\ForbiddenHttpException('You are not authorized to do this.');
            }
    
        }
    }
    

    如果您需要在模型级别执行此操作,则需要使用 addError() 方法而不是直接抛出错误。调用 validate 方法时,您的模型实例将持有它。然后在您的操作中,您可以简单地返回它。它将被序列化,错误将以正确的格式输出。有很多方法可以实现这一目标。一个简单的例子可能是使用load 方法在验证之前将查询和正文参数传递给模型(可能需要场景):

    $queryParams = Yii::$app->request->queryParams;
    $bodyParams  = Yii::$app->request->bodyParams;
    
    $params = array_merge($queryParams,$bodyParams );
    
    $model = new $modelClass;
    $model->load($params , '');
    
    if ($model->validate() === false) return $model;
    else {
       // do whatever you need
    }
    

    【讨论】:

    • 您缺少右大括号 if (!isset($params['language']))。无论如何,这行得通,但为什么 checkAccess 和为什么 ForbiddenHttpException ?在我看来,将参数验证称为访问检查并不符合语义。还是我错了?
    • 您可以在那里抛出您需要的任何类型的错误,因为您的错误消息将在那里序列化,因为您的控制器的内容协商器过滤器将适用。我个人会在模型级别进行。检查我的更新
    • 好的,当我这样做时,我得到了验证,我得到了错误:` $model = new $this->modelClass; $queryParams = Yii::$app->request->queryParams; $bodyParams = Yii::$app->request->bodyParams; $params = array_merge($queryParams,$bodyParams); $model->load($params, ''); if (!$model->validate()) { return $model; }` 但格式错误:[ { "field": "language", "message": "Language cannot be blank." } ] 我想要 JSON 响应,就像我在问题中描述的那样。它需要有状态
    • 我决定使用第一种方法,因为我发现它对我目前的情况不太糟糕。我需要根据需要使用多少来创建响应来验证 x 模型。我宁愿将验证逻辑保留在我的 Validator 类中的一个位置,然后从基本控制器的 checkAccess 方法中调用它。感谢帮助。我对 yii2 解决方案感到非常失望。
    • UnprocessableEntityHttpExceptionForbiddenHttpException 都是 yii\web\HttpException。起初我认为它是负责该序列化的 contentNegociator 但现在正如你提到的那样,我可能错误地认为这是唯一的方法,因为 ForbiddenHttpException 是直接从用户类中抛出而不通过控制器。当我在家的电脑前时,我会检查它是如何工作的。如果我找到更好的解决方案,我会更新我的答案。如果其他人想出更好的答案。在这种情况下,我建议选择他的答案而不是我的答案。
    猜你喜欢
    • 2011-09-02
    • 1970-01-01
    • 1970-01-01
    • 2020-05-29
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 2016-07-25
    • 2016-10-17
    相关资源
    最近更新 更多