业务报错 ¶
作者:KK
发表日期:2016.8.18
根据我的开发经验总结,通常,注意是通常我们应该把报错方式分为2大类:业务报错
和程序报错
,本文章先专门讲一下业务报错
基本理论 ¶
假如一个发布文章的接口,文档如下:
接口地址:/article/publish.do
请求方式:POST
参数1:title 文章标题,6到30个字符
参数2:content 文章内容
参数3:category_id 文章分类ID
返回值:。。。省略
于是前端在提交文章信息给后台时,如果缺少了title,那后台校验过程中应该返回失败的标识给前端,让前端知道“缺少文章标题”,但这只是前端给来的参数不及格而已,判断不通过就返回给前端就好了,并不是后台的错误,所以这种失败的返回可以理解为我说的业务报错
:
if(!strlen($title)){
$this->ajaxReturn('请输入文章标题', 0);
}
并且在这种情况下,后台肯定不用记录程序日志啊,根本就是前端参数有问题嘛
参数内容不正确也还是前端的错,后端没错 ¶
接上面例子,如果前端给了标题来,可是长度不足,那还是前端的错,当然其实大家的代码都会对文章标题做长度判断
好了可是如果前端发了个数组过来呢?就是说$title不是个字符串,而是一个数组,这时候就不同了,由于大部分菜鸟程序员不会对类型进行校验,于是在拼接SQL的时候就出错了
没错出错的话一般都不会入库并且错误停止下来,程序大可说一句“他类型不对就不会入库啊”,但别忘了这时候通常程序框架都会产生程序日志,说哪里哪里拼接SQL的时候出错了
首先我这里明确一下:程序日志通常是反映了程序有问题,把问题的相关信息记录下来给程序员去排查用的
,所以在这种情况下因为客户端请求过来的数据有问题导致了产生日志,可是实际上问题是客户端不老实,不按照文档约定去写接口参数的值嘛,所以后端程序员通常都会因为排查老久后发现是客户端发送的数据有问题,于是叫客户端修正参数的值类型并且给代码增加一个类型校验来防止日志再次产生
好了这里注意,程序员通常都会补充校验而不是发现了客户端的问题后就公认驻指望客户端去调整自身,那运行效果就回到了一个这样的状态:客户端如果又发送数组的title值给服务端,服务端这回校验到类型不对了,直接告诉了客户端“非法的参数类型”或“错误的文章标题”啥的,嘿嘿这是不是后端就不会产生日志了呢?——没错确实是不会产生日志的
所以最终回到了我的一个结论:由客户端参数不正确引发的错误不是服务端程序错误,服务端程序不应该产生日志
最终大家的BUG修改结果方向都会往这个方向推进(除非刻意侦听某类非法数据的攻击)
小结 ¶
我对业务报错的定义就是这样:服务端的业务接口定义了请求参数的约束后,如果客户端不按照这个约定发送参数导致业务逻辑无法正常进行,那是客户端的问题,服务端的程序一点都没有错误,所以服务端不应该产生程序日志
要做到业务报错的标准也很简单:对请求参数进行完善的校验处理即可
如果客户端的参数都通过了服务端的校验,然后服务端自己程序的过程中居然出了问题,这才是程序错误,需要进行日志记录
我之所以特别说明这个,是因为我看到很多普通程序员在处理参数的校验时都没有进行完整的校验并且导致了程序日志的产生
提供业务报错的方式 ¶
像TP框架那样,用控制器的ajaxReturn返回json给前端去判断成败是其中一种提供业务报错的方式,用其它框架也是,想办法封装或使用一个能快捷返回业务报错的方法就好了
我以前有个项目是自主开发的框架,定义了这样一个函数来返回报错,可以供一些菜鸟参考一下思想,其实没啥,就跟TP的差不多:
/** * 返回业务操作结果 * @param string $message 提示消息 * @param int $code 结果代码,0=成功,其它都是不成功,可以自己定义不成功的类型 * @param mixed $data 附加数据,非AJAX下不会显示在页面上 */ function alert($message, $code = 1, $data = null){ if(IS_AJAX){ header('Content-type:application/json'); $json = json_encode([ 'message' => $message, 'code' => $code, 'data' => $data, ]); if(json_last_error()){ throw new ErrorException('返回JSON失败'); } exit($json); }else{ $view->display('system/result', [ 'message' => $message, 'code' => $code, 'data' => $data, ]); //一个HTML字符串,显示message,根据code显示不同颜色什么的 exit; } }
上面不是完整的代码,就表达一下意思哈,调用就这样嘛:
if(!strlen($title)){ alert('请输入文章标题', 0); }