多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 前言 ***** Thinkphp5+ 是一款非常适合API开发的框架,Web安全法则中有非常重要的一条,那就是"永远不要相信用户的输入",所以在接口开发中 一定避免不了数据验证,比如最初级的写法可能是这样子的: ## 初级写法 ```php <?php namespace app\index\user; public function register() { $request = request(); $params = $request->param(); if (empty($params['user_name'])) { return json(['code' => -1, 'msg' => '请输入账号']); } if (!preg_match('/^[a-z0-9]$/i', $params['user_name'])) { return json(['code' => -1, 'msg' => '账号只能是英文和数字']); } if (empty($params['password'])) { return json(['code' => -1, 'msg' => '请输入密码']); } //todo ...各种判断通过后 再进行实际的业务逻辑 } ``` 额,或许我们一个注册接口的判断代码 维护起来都有十几二十行了,万一什么时候 Boss说我们的接口要支持返回xml格式,那岂不是又得加班了? 我们有没有更优雅高效的写法? 当然有, 我们先了解一下 [Thinkphp5.1验证器定义](https://www.kancloud.cn/manual/thinkphp5_1/354102) 我们可以先定义一个验证器 ``` namespace app\test\validate; use think\Validate; class User extends Validate protected $rule = [ 'user_name' => 'require|alphaNum', 'password' => 'require', ]; protected $message = [ 'user_name.require' => '请输入账号', 'user_name.alphaNum' => '账号只能是数字和字母', 'password.require' => '请输入密码', ]; protected $scene = [ 'login' => ['user_name', 'password'], 'register' => ['user_name', 'password'], ]; ``` 然后 我们再控制器中 就可以这样写了 ## 中级写法 ```php <?php namespace app\test\user; public function register() { $request = request(); $params = $request->param(); $validate = new \app\test\validate\User; if (!$validate->scene('register')->check($params)) { return json(['code' => -1, 'msg' => $validate->getError()]); } //todo ...再进行实际的业务逻辑 } ``` >[warning] 请注意Thinkphp5.1.6+之后的版本才支持中间件。 > 这样 我们就可以不需要在控制器中写一大片的各种判断了,比如 突然要限制账号最多为18位,也只需要在验证器中增加一条[验证规则](https://www.kancloud.cn/manual/thinkphp5_1/354107)就行了,非常灵活! 你以为本文结束了吗? 当然没有,API开发涉及的接口 可能非常多 注册 登录 编辑 等 所以如果我们有多个接口的时候 可能代码是下面这样的 ```php <?php namespace app\test\user; public function register() { $request = request(); $params = $request->param(); $validate = new \app\test\validate\User; if (!$validate->scene('register')->check($params)) { return json(['code' => -1, 'msg' => $validate->getError()]); } //todo ...再进行实际的业务逻辑 } public function login() { $request = request(); $params = $request->param(); $validate = new \app\test\validate\User; if (!$validate->scene('login')->check($params)) { return json(['code' => -1, 'msg' => $validate->getError()]); } //todo ...再进行实际的业务逻辑 } //还有无数个接口 ``` 额,看起来并不是很完美优雅,要是有100个接口 岂不是每个方法前面都是雷同相似的代码, 如果有什么办法 能够再执行每个方法之前 都自动判断参数和规则 那就完美了, 接下来我们要出场的是 [Thinkphp5.16+ 中间件](https://www.kancloud.cn/manual/thinkphp5_1/564279),通过阅读官方开发手册,我们了解到了中间件主要用于拦截或过滤应用的HTTP请求,并进行必要的业务处理。那正符合本文中需要解决的场景. 首先我们在 application/test/middleware 目录中创建 中间件文件 Validate.php ```php <?php namespace app\test\middleware; use think\Controller; class Validate extends Controller { /** * 默认返回资源类型 * @var \think\Request $request * @var mixed $next * @var string $name * @throws \Exception * @return mixed */ public function handle($request, \Closure $next, $name) { //获取当前参数 $params = $request->param(); //获取访问模块 $module = $request->module(); //获取访问控制器 $controller = ucfirst($request->controller()); //获取操作名,用于验证场景scene $scene = $request->action(); $validate = "app\\" . $module . "\\validate\\" . $controller; //仅当验证器存在时 进行校验 if (class_exists($validate)) { $v = $this->app->validate($validate); if ($v->hasScene($scene)) { //仅当存在验证场景才校验 $result = $this->validate($params, $validate . '.' . $scene); if (true !== $result) { //校验不通过则直接返回错误信息 return json(['code' => -1, 'msg' => $result]); } } } return $next($request); } } ``` 然后在application\test 目录下 新建middleware.php ```php <?php // 中间件扩展定义文件 return [ 'validate' => app\test\middleware\Validate::class ]; ``` ![](https://box.kancloud.cn/f812e9bed5567f384efdd722cc938163_1447x368.png) 最终,在控制器中的代码我们可以简化成如下 ## 高级写法 ```php <?php namespace app\test\user; public function register() { $request = request(); $params = $request->param(); //todo ...此时校验已经通过,可直接进行实际的业务逻辑 } public function login() { $request = request(); $params = $request->param(); //todo ...此时校验已经通过,可直接进行实际的业务逻辑 } //更多其他接口 ``` 对的,就是这么神奇, 我们只需要维护 application/test/validate 文件夹中的User.php(必须和控制器文件名完全一致) 文件即可 比如 新增了编辑用户 edit方法,我们只需要在User.php中 $scene 添加 命名为edit(必须和控制器中action方法名完全一致),这样控制器和验证器分离, 代码瞬间简洁很多,维护也变得非常方便了, 让我们测试一下 直接访问127.0.0.1/test/user/login ,我们看到已经自动校验了! ![](https://box.kancloud.cn/98d07fdb1389bba708fbd76db63561d2_617x163.png) # 后记 ***** ## 开发帮助及交流 如您对本文感兴趣想与我联系交流 您可以 + 邮件至:xieyongfa@ecarde.cn + QQ:2392523899 [点我聊天](http://wpa.qq.com/msgrd?v=3&uin=2392523899&site=qq&menu=yes&from=message&isappinstalled=0) + 微信交流 ![](https://box.kancloud.cn/b74285a950ce81e3cb782f02eb118d59_752x974.jpg =300x389)