php api 参数验证,【中间件】API开发实现自动校验参数

# 前言

*****

Thinkphp5+ 是一款非常适合API开发的框架,Web安全法则中有非常重要的一条,那就是"永远不要相信用户的输入",所以在接口开发中 一定避免不了数据验证,比如最初级的写法可能是这样子的:

## 初级写法

```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

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

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

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

// 中间件扩展定义文件

return [

'validate' => app\test\middleware\Validate::class

];

```

![](https://box.kancloud.cn/f812e9bed5567f384efdd722cc938163_1447x368.png)

最终,在控制器中的代码我们可以简化成如下

## 高级写法

```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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值