Thinkphp 6 验证器实践

在api开发中不可避免的需要验证接口参数的正确性,在以往的开发中常常是在控制器接收参数并进行验证,这种方式一个比较大的缺点是每个控制器都需要单独写,代码冗余并且会有许多重复代码。

常规方式如下:


public function login(){

    $username = $this->request->param("username",'');

    if(!$username){
        return json(["msg"=>"请填写账号"]);
    }

    $password = $this->request->param('password','');

    if(!$username){
        return json(["msg"=>"请输入密码"]);
    }
}

引入验证器之后的编写方式如下:

// 验证器定义
class LoginValidate extends Validate
{
    protected $rule = [
        'username'  => 'require',
        'password'  => 'require',
    ];

    protected $message = [
        'username.require'  => '用户名不能为空',
        'password.require'  => '密码不能为空',
    ];

    protected $scene = [
        'login'=>['username','password']
    ];
}

// `Login控制器` 
public function login(){

    $params = $this->request->params();

    $v = new LoginValidate();

    $validateResult = $v->sence("login")->check($params);

    if(!validateResult){
        return json(["msg"=>$v->getError()]);
    }
}

这种模式相较于前面的是比较统一简洁,但是不可避免的还是会遇到一些重复的繁琐步骤。

最终想法是统一在中间件中做校验。

先定义一个参数校验中间件 ParamsValidateMiddleware

class ParamsValidateMiddleware
{
    public function handle($request, $next)
    {
        //获取当前参数
        $params = $request->param();
        //获取访问模块
        $module = str_replace("/","",$request->root());
        //获取访问控制器
        $controller = explode('.',$request->controller());
        $controller[count($controller)-1] =ucfirst($controller[count($controller)-1]);

        //获取操作名,用于验证场景scene
        $scene    = $request->action();
        $validate = "app\\" . $module . "\\validate\\" . implode("\\",$controller);
        //仅当验证器存在时 进行校验
        if (class_exists($validate) && $request->isAjax()) {
            $v = new $validate();
            if ($v->hasScene($scene)) {
                //仅当存在验证场景才校验
                $result = $v->scene($scene)->check($params);
                if (true !== $result) {
                    //校验不通过则抛出异常,留后面自定义异常获取
                    throw new ValidateException($result);
                }
            }
        }
        return $next($request);
    }
}

思路是找到对应控制器下的场景,例如 AccountValidate 验证器中定义场景 login,然后访问控制器 Accountlogin 方法时,就自动查找验证类,如果有定义对应的场景就进行验证,如果没有定义的话就忽略。

然后在路由配置文件中(route.php)定义中间件

注意:一定要在路由文件中引入或者路由配置文件中引入,抑或是控制器中引入。
如果是在全局路由配置的话就获取不到控制器内容。


return [
    'middleware' => [
        // 参数自动验证中间件
        ParamsValidateMiddleware::class,
    ]
];

2021-10月补充

基于上面的中间件参数验证方案,还存在一个弊端,就是不够灵活,如果某个场景下需要单独验证时比较麻烦。

恰好最近看到一个注解验证

首先安装注解 composer require topthink/think-annotation

然后在需要灵活配置的入口函数新增注解,如下


class Index
{
    /**
     * @Validate(IndexValidate::class,scene="create",batch="true")
     * @return mixed
     * @Route("hello")
     */
    public function hello()
    {
        return 'hello, TP6 Annotation  Validate';
    }
}

这样就会自动跟踪到 IndexValidatecreate 场景中并自动进行参数校验。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇