我需要拍砖 和 看见你们的意见,为团队少挖坑

场景:创建订单

实际流程:

终端调用(PC端、移动端APP、微信端、Web端)-->控制器 或 接口-->实际的业务处理-->控制器 或 接口-->终端做出相应处理(控制器可能是渲染对应页面; 接口返回 JSON数据)

业务处理类动作:

检查用户是否登陆

验证商品 ID、购买数量等参数

检查该商品是否处于上架中

检查该商品是否可以购买

各种检查...

创建订单

记录 Log

返回订单创建结果给调用者

创建失败:...

创建成功:[return true|return Order info]

游戏规则

前后端数据格式约定为 JSON格式如下:

{

code: "00000", // 状态码

msg: "操作成功!", // 提示信息

data: {} // 数据

}

注:"00000":业务成功状态码;非"00000"都为业务失败。

为了防止服务器端状态码泛滥成灾,code可以为"",这时 msg 里面则是相应的错误信息,只为给用户提示。

导火线

项目开发完毕,测试人员去测试,提如下Bug:

如果用户未登录,进个人中心,提示用户未登录,然后会去登陆view;而在下单页,提示用户未登录,却没有去登陆view。

然后前端童鞋开始去修复该问题,查出如下问题:

个人中心服务器接口返回的数据格式:

{

code: "00008",

msg: "用户未登录,请登录",

data: [ ]

}

下单页服务器接口返回的数据格式:

{

code: "",

msg: "用户未登录,请登录!",

data: [ ]

}

然后前端童鞋对服务器端童鞋讲,这里你应该返回给我code: "00008",我这边一看 code便知是用户未登录,就可以做出相应的操作,这里你只返回提示信息,我这边不好做更加细腻的操作。

然后,后端童鞋开始尝试给该地方添加上 code。

开始着手修改代码:

首先找到接口方法里面发现如下 demo:

php$order = kernel::single('sysapi_ecoupon_order')->create($params, $msg);

if (!$order) {

return array('code' => '', 'data' => array(), 'msg' => $msg);

}

return array('code' => '00000', 'data' => $order);

改方法返回array(); 在外部统一入口、出口处再返回 JSON出去。

sysapi_ecoupon_order

phppublic function createNew($params, & $msg)

{

// 获取用户信息

$member_info = app::get('b2c')->model('members')->get_current_member();

if (empty($member_info)) {

$msg = app::get('ecoupon')->_('用户未登录,请登录!');

return false;

}

// 继续下面的业务处理

}

接口调用的kernel::single('sysapi_ecoupon_order')->create($params, $msg);这里面做实际的业务处理,错误信息是通过 $msg 向上传递出去,外部没办法通过 $msg 获知对应的 code。然后给前端童鞋讲这种情况没办法返回 code给你。

前端就只能通过判断 msg的方式来修复该问题

然后写了如下 demo:

javascriptif("用户未登录,请登录!" == data.msg) {

// 用户未登录,去登录

// ...

}

然后提交,测试,通过,上线,N天后

有人跑过来讲:下单页 与 个人中心的提示有点不同,貌似多了个 "!"。(举例而已,更多的可能是提示不友好、错别字等情况)

然后后端同学修改为 $msg = app::get('ecoupon')->_('用户未登录,请登录'); 提交,测试不通过,前端同学再修改为if("用户未登录,请登录" == data.msg),提交,测试通过

// 如此反反复复

终究有一天:产品、测试,前端、后端混战了一场。N人,卒.....

重新正视问题

最终前后端得出结论:要想对用户实现更加友好的体验,前后端数据必须有个标识具有唯一性,不变性。而现在用的 msg却不具备,还是得用 code。并且这里前后端极度耦合msg。

后端童鞋回来继续修改代码,开始着手给这里添加上相应的 code。

开始思考该怎么添加 code,现在的问题是 create( ) 方法可能是其他童鞋开发,内部返回的提示信息,我这边是调用者,不能确定方法内部到底会返回什么提示信息,无解。

忽然,有一天想到,我在调用该方法之前检查下用户有没有登录就OK了,然后开始写如下实现:

public function create($params)

{

$member = app::get('b2c')->model('members')->get_current_member();

// 登录验证

if (empty($member)) {

return array('code' => '00008');

}

$msg = '';

$order = kernel::single('sysapi_ecoupon_order')->create($params, $msg);

if (!$order) {

return array('code' => '', 'data' => array(), 'msg' => $msg);

}

return array('code' => '00000', 'data' => $order);

}

呵呵,好机智的少年。

然后告诉前端,这里可以返回 code了,前端愉快的删掉原来那坨判断 msg的代码,而在 ajax请求的地方统一判断 code就能预知用户未登录,做出相应的操作。

经测试,上线。一切又回到了美好时光。

随着时光的流逝,业务的增加,后端童靴发现Order类里面如下 demo:

phppublic function create($params)

{

$member = app::get('b2c')->model('members')->get_current_member();

// 登录验证

if (empty($member)) {

return array('code' => '00008');

}

// 实际业务处理....

}

public function getOrderList($params)

{

$member = app::get('b2c')->model('members')->get_current_member();

// 登录验证

if (empty($member)) {

return array('code' => '00008');

}

// 实际业务处理....

}

public function getOrderDetail($params)

{

$member = app::get('b2c')->model('members')->get_current_member();

// 登录验证

if (empty($member)) {

return array('code' => '00008');

}

// 实际业务处理....

}

// ...

这都是什么玩意............ 然后开始封装,稍微好了点

又过了一段时间,有人过来说创建订单还需要优化体验,

点击创建订单提示如下:

超过最大购买量——给出提示,继续留在创建订单页

该商品已卖光或已下架——引导用户去商品列表页

这时,前端童鞋告诉后端童鞋,商品下架的时候,你也应该返回一个状态码。

后端童鞋开始打算添加 code,发现如下 demo

phpkernel::single('sysapi_ecoupon_order')->create($params, $msg);

这里的提示信息是 $msg 返回的,用户登录外部可以提前检测,这里的商品能否购买要实现添加 code也需要提前检测,将来要是需要添加类是功能岂不是...... 每需要一个精确的 code返回出去,这里就需要添加检测,这里代码将会变得无法直视。

况且这里本该在业务里面检测,一切不那么友好起来了。

再次思考,代码写的不爽了,一定是哪里不对

问题所在

开始怀疑 public function create($params, & $msg) { } 这里不应该是通过 & $msg 来作为 调用者与 被调用者之间的 错误信息通信约定,一切的问题都出在了这里。错误消息向上传播的约定不合适

如果这里约定的是 code作为错误向上传播一切的问题即将不复存在。在调用业务方法之前的检测代码就都可以去掉了,代码简约,一切又美好起来。

接下来继续思考,使用 code作为业务处理失败消息传递问题又来了

现在已有的业务代码都是如此定义public function create($params, & $msg),怎样更加友好的替换成 code

如果使用 code,code只能服务器端 与 前端约定的一个具有唯一性的标识(code 比 msg 对国际化的实现更加容易)但是并不能直接展示给用户,那么就需要定义每个 code 的代表的意义 与 对应的提示信息。那么问题来了,code 应该已怎样规范来定义所代表的含义

再来看如下常用的两种方法定义:

public function create($params, & $msg)

public function create($goodsId, $num, & $msg)

第一种方式,参数通过一个 $params数组传递过来,方法内部在把错误提示放到 $msg中。

好处:$params是个数组,里面参数可以任意添加

缺点:该方法调用者在外部不能知道该方法需要什么参数,必须来看该方法内部实现,做出对应的数组 key的转换(如: user_id 转 userId)。方法调用者 与 方法实现 极度耦合。维护成本大、出Bug系数高

第二种方式,按基本类型分别传递单个参数

好处:方法调用者根据方法定义就能够知道方法具体需要的参数,调用方法时不需要作 key转换,只需要传递对应的参数即可

缺点:参数数目过多时,惨不忍睹

这里有如下问题:

这里如何已一种更加容易维护,扩展的方式来处理(Java里面方法参数已对象的方式传递可以借鉴)

这里的& $msg 真的合适吗,如果是第二种方式定义的方法,以后扩展个 $phone 该如何处理?public function create($goodsId, $num, & $msg, $phone='')这样么?怎么看怎么蛋疼

再来看不通过 & $msg传递错误信息之后的代码

phppublic function create($goodsId, $num)

{

if ( ? ) {

// 返回状态码

return '0001';

}

if ( ? ) {

// 返回状态码

return '0002';

}

// 创建订单

// ...

// 返回订单信息

return $order;

}

看似实现了,但是方法调用者,怎么调用怎么蛋疼,一会返回状态码,一会返回订单信息,完全两种类型。

综合以上问题:

得出以下结论:

业务处理失败消息要以 code 的方式向上传递给调用者

业务处理失败消息以参数的方式传递不是很适合,并且不能以 return的方式返回

再次思考,最终从 Java里面想到了一点思路(幸好是 Java出身。疑问:为何面试的时候 Java的工作经验都不算在 PHP工作经验里呢,并没有因此而加分)

解决方案:

自定义一个异常类,包括 codo属性 和 msg 属性

凡是遇到业务不能正常处理的时候就创建一个异常对象,设置对应的 code 或者 msg属性(为了减少 code泛滥,这里的 code 与 msg 可以2选一,如果前端需要做精准的处理,就设置 code,如果只是为了给用户提示,就只返回 msg,则可以减少一个 code),然后抛出异常

方法调用者在外部统一捕捉该异常,如 接口的统一入口出口的方法内部处理

因个人工作时间、项目经历不多、归根结底经验不足。现在将该方案写下来,还望有经验的大神拍砖,以免给团队挖坑,以上 $msg 就是 N久以前埋下的坑。

php服务器端验证失败,PHP 服务器端内部业务处理失败消息传递方式相关推荐

  1. 客户端验证不能代表服务器端验证

    比如设置取款额度不能大于100元, 客户端写法如下: <asp:Button ID="txtSubmit" runat="server"  OnClien ...

  2. C# 视频监控系列(10):服务器端——验证、设置画面质量、字幕叠加、板卡序列号...

    C# 视频监控系列(10):服务器端--验证.设置画面质量.字幕叠加.板卡序列号 豆豆网   技术应用频道   2009年04月08日  [字号:小 中 大] 收藏本文 被过滤广告 关键字: NetB ...

  3. FineUI(开源版)v6.0中FState服务器端验证的实现原理

    前言 1. FineUI(开源版)是完整开源,最早发起于 2008-04,下载全部源代码:http://fineui.codeplex.com/ 2. 你可以通过捐赠作者来支持FineUI(开源版)的 ...

  4. tplink连接服务器失败_管家婆财贸双全连接失败,服务器端没有找到加密狗

    管家婆财贸双全连接失败,服务器端没有找到加密狗 管家婆财贸双全找不到狗判断步骤 1.先判断电脑能否识别管家婆财贸双全加密狗我的电脑--右键--属性--硬件--设备管理器--通用串行总线控制器(或人体学 ...

  5. CustomValidator,客户端,服务器端验证

    转一篇CustomValidator,客户端,服务器端验证 的案例 <%@ Page Language="C#" %> <script runat="s ...

  6. 印象笔记不能同步 显示服务器端出现,印象笔记同步失败,服务器端出现问题...

    印象笔记同步失败,服务器端出现问题0 Log opened on 2013/12/05 09:47:01 (UTC+8:00) 09:47:01 [4848] Command line: " ...

  7. 苹果官网php,苹果官方购买产品服务器端验证代码PHP版

    苹果官方购买产品服务器端验证代码PHP版 function getReceiptData($receipt, $isSandbox=false) { if($isSandbox){ $endpoint ...

  8. 计算机调试致sa登录失败,无法打开登录 'xxxx' 中请求的数据库。登录失败。用户 'sa' 登录失败。解决思路...

    当前位置:我的异常网» Sql Server » 无法打开登录 'xxxx' 中请求的数据库.登录失败.用 无法打开登录 'xxxx' 中请求的数据库.登录失败.用户 'sa' 登录失败.解决思路 w ...

  9. linux消息通信无法接收,求助!Linux基于UDP通信失败,server接收不到消息???...

    代码参考<Linux C从入门到精通>,实践的时候发现失败,求助!!! server端代码如下: /*服务器端*/ #include #include #include #include ...

  10. 剑网3 修复 连接服务器失败,剑网三重制版更新失败修复失败 | 手游网游页游攻略大全...

    发布时间:2016-05-30 国产精品网游的单机新作自从去年公布了几张截图之后似乎就没有了消息.而其制作人郭炜炜近期在接受媒体采访的时候谈到了. 标签: 游戏资讯 游戏新闻 发布时间:2016-05 ...

最新文章

  1. CORDIC算法——圆周系统之旋转模式
  2. 代码整洁之道(一)最佳实践小结
  3. 关于大型网站技术演进的思考(一)--存储的瓶颈(上)
  4. mysql回收权限_mysql回收权限不成功,请问如何破?
  5. 全球及中国重型设备备件行业发展动态及未来趋势调研报告2021年版
  6. Spring AOP编程-传统AOP开发切点表达式写法介绍
  7. va_list函数族应用
  8. 异步fifo_数字IC校招基础知识点复习(五)——跨时钟域涉及part2(异步FIFO)
  9. CPDA|数据分析很难学?分享最有效的学习路径!
  10. python刷网课程序,基于python和selenium的刷网课的代码
  11. vscode启动Python调试 找不到指定模块
  12. 十六进制编辑器HxD Hex Editor x64 v2.3.0.0
  13. termux—手机远程连接服务器教程
  14. 【.Net开发】之WPF入门介绍
  15. 集火全屋智能“后装市场”,真正玩得转的没几个
  16. 学计算机核显足够了吗,独立显卡、核心显卡和集成显卡的区别
  17. Android 外部存储App私有目录下照片和视频显示到相册
  18. iOS越狱程序开发框架
  19. 信息安全的马其顿防线
  20. CSDN文章编辑技巧

热门文章

  1. Java高低位和byte转int
  2. 村上春树专访:将考虑在BOBO发行NFT作品
  3. 携手共进——再答丁又专老师
  4. 移动互联网(一)短信和彩信界面开发包
  5. 判断出栈顺序合法性的两种方法
  6. 计算机毕业设计Node.js+uniapp安卓基于Android的物流快递app(源码+程序+lw+远程调试)
  7. 颜色管理出问题:windows照片查看器无法显示此图片 因为内存不足。
  8. 活动单导学计算机课,活动单导学 自主式研学
  9. Jquery 循环遍历input求合计
  10. librosa语音信号处理