前言
下文是我对API验证层的疑问和观点,主要是验证层这一层的工作内容。
这些观点的具体应用,迟些我用代码写出来~
正文
先说下使用API的的一般流程
客户端发请求:路由解析->控制器->验证层->(服务层|逻辑层)->数据库模型层操作数据库->返回固定格式的数据,当然当中包括全局的异常处理层。
可以看到,一个请求,分了很多层去处理。为什么要分层?一个原因是:
开发软件本身是一件很复杂的事情(必须认识到这一点)。而我们人类大脑的能力是有限的,不可能同时处理太多的复杂性。我们可以通过将复杂性分解、抽象、分层,一次只需要处理一个部分复杂性,而不是所有。
每一层负责本层的工作,合起来才能完成最终的工作,那么验证层这一层,负责什么呢?验证数据,废话,验证什么数据?例如,**参数是否有传?手机或邮件格式?账号是否存在?哪些要在验证器验证?其次,期望传入的参数,我们肯定会写验证规则,但不期望的呢,要过滤掉吗?最后,验证不通过,返回什么信息?
一、验证层要验证什么
笔者认为,无业务语义的验证(这些验证比较通用),放在验证层,而涉及数据库操作的验证,放在模型层(服务层|逻辑层|数据库访问层)。
因为
- 有业务语义的校验,通常需要访问数据库,如果也放在验证层,验证通过,到处理这些数据时,又要操作一下数据库,重复了,重复意味着,效率低了,且修改要改2个地方。
- 验证层验证了非空,和格式,后面模型处理数据时会流畅,省心很多,不用
isset()
判断是否存在。
即,放在验证层的有
- 非空验证。
- 数据格式验证,手机,邮箱,身份证等。
其它,放在模型层,如,**账号已存在,商品库存不足…
二、验证层要过滤非期望字段吗
例如,用户注册,后端期望接收username
,password
参数,在验证器对其作了require
和格式相关验证,验证通过,往下,模型层验证账号是否已存在,不存在,则插入数据库,返回成功。
这个过程很流畅,但如果,客户端传了多传了data_state
参数呢?(这是数据状态字段,每个数据表都有,1代表正常,0代表已删除)。
如果粗心大意,直接将传过来的data,保存进数据库,就会出现注册成功一个已删除用户的情况,显然是bug。
即我们除了要对期望参数作验证,还要过滤掉非期望参数。
要放在验证器过滤吗?这与框架有关,有的框架设计成:验证不通过就抛异常,通过就返回过滤后的数据,我认为这样也合理。
但tp5下不应该这样做,有更好的方式:
- 要么在控制器只接收期望参数。(推荐这种)
$data = $this->request->only(['username', 'password']);
- 要么,在模型层,赋值一遍处理
$saveData = $data['username'];
$saveData = $data['password'];
// 然后最终插入数据库的是saveData
注意:除了增改数据,查询数据也要注意过滤非期望参数,如,传了不属于数据表的字段查询条件,没过滤掉,直接之心sql语句,肯定报错,也属于bug。
三、验证不通过,要返回什么
返回错误信息,废话,返回怎样的错误信息?举个例子吧,默认情况下,语言包设置成中文,username参数没传,会返回username不能为空,这就可以了吗?
我们平时访问的app,网站,返回的信息好像更友好些吧,亲,用户名不能为空哦~
有人认为,这是前端干的活,后端返回注册是否成功即可,前端显示什么文字是前端的事,这是一个观点。
但我认为,提示信息,更应该在后端设置。原因如下:
- 提示信息应该各个端统一,手机端,app端,小程序,调用的是同一套接口。如果都在前端写,要改,真的挺麻烦的。
- app,小程序上架要等待审核,要改,还不能马上就改好。
所有,放到后端,修改起来会方便很多,前端处理也会方便些,直接弹出提示信息好了。
即,验证不通过,验证层要返回用户友好的提示信息。
总结
- 验证层只做非空和格式验证。
- 验证层是否要过滤非期望字段与框架设计有关,tp5的不应该在验证层过滤。
- 验证不通过,验证层要返回用户友好的提示信息。
以上就是验证层要干的所有工作,不属于的,就放到其它层。