资讯专栏INFORMATION COLUMN

一次和前端的相互甩锅的问题记录

bergwhite / 3300人阅读

摘要:如果没有要求,前端直接展示后端返回的错误消息。为了统一异常处理,一般公司的做法都是统一返回一套数据格式,码,代表正常,其他表示异常。那么前端处理异常的逻辑这次的问题就是走到的分支了。和前端讨论了下,确定了解法。

背景

我们在APP上有个功能,需要获取用户当前定位,然后当用户关闭了GPS后,没有获取到用户定位,会触发一个bug,弹窗内容如下。

问题分析

这个问题的直接原因就是移动端的值取不到,导致没有给变量赋值,就将"undefined"传给了后端,后端的这个值定义的Integer,类型转换失败,报错。

深层原因是异常处理机制有问题,于是后端和前端开始撕逼了

前端观点: 后端代码太不健壮了, 就算前端传错了,也应该具备容错性;此外APP是有版本的,就算hotfix,用户也不一定升级,上一版本用户还是会有问题,所以这种问题尽量是后端来修复。

后端观点:前端没有异常兜底机制,用户不应该看到任何这种程序异常。对于有定制需求的异常,报特定异常,没有应该显示通用异常,比如弹窗"服务不可用"。另外这种属于http请求层面的约束,前端不遵从约束,还来怪我。我后端框架层面就给你拦截了,没到业务代码。

双方说的都好有道理,谁也说服不了谁。但是关于目标大家达成一致:坚决不能让用户看到这种类型的弹窗异常。

既然说服不了对方,就只能从更深入的分析问题,看看更合理的解法

通用异常的处理方式

http通常错误有

4开头:客户端参数有问题,需要后端提供debug信息。理论上应该只是联调的时候会出现,但是实际上不一定(这不就打脸了吗)

5开头:服务器端有错误,客户端有统一提供的异常处理

2开头:业务异常,如果有UI要求,后端返回一个code码,前端根据code码,展示UI。如果没有UI要求,前端直接展示后端返回的错误消息。

为了统一异常处理,一般公司的做法都是API统一返回一套数据格式,

{
    "error_code": "xx", // code码,1代表正常,其他表示异常。
    "error_msg": "xx" // msg,错误提示消息
    "data": "xx" // 正常数据
}

我们也是,并且将4开头的都统一处理成这套统一的数据格式。

那么前端处理异常的逻辑

这次的问题就是走到2的分支了。

前后端都没做错,问题是后端对于异常模型的抽象有问题,客户端参数有问题,需要后端提供debug信息,而不是给用户展示的错误信息。

其实服务端对于异常就分三种

客户端参数有问题的异常(前端需要debug信息和错误msg信息)

需要用户知道的业务异常,前端需要根据code展示的(前端需要code码)

通用的服务端异常,包装成消息给前端。(前端需要错误msg信息)

解法

分析清楚了问题后,就有了解法。

解法1:错误消息和debug消息分离,返回的API统一格式中增加一种字段。debug_msg 给开发看的,error_msg 还是给用户看的

解法2:定义几个枚举code。作为开发的约定

code error_msg 参数错误含义
010000 系统错误[010000] 请求方法不支持
010001 系统错误[010001] 缺少路径参数
010002 系统错误[010002] 缺少必须的请求参数
010003 系统错误[010003] 类型不匹配
010004 系统错误[010004] 请求体异常
010005 系统错误[010005] // 参数校验异常(body 或 param)
010006 系统错误[010006] 参数绑定异常(表单)

解法1定义比较清晰,但是为了这种corner case增加了一个字段的开销,网络传输代价高了。另外还需要前端配合更改,改动成本比较大。

解法2兼容了现在的实现,前端不用更改,但是对于客户端参数有问题这种错误提醒不是很友好,不能向前端显示具体的参数错误了。只能打日志。

和前端讨论了下,确定了解法2。

总结

所以这个问题,最后的解法

前端获取不到定位时,将undefined这个变量赋值

后端针对移动端这个服务,改动了异常处理机制

@RestControllerAdvice
public class ApiStandardException {
    private static final String ERROR_MSG = "系统错误";
 
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity handle(final Exception ex, final WebRequest request)
            throws Exception {

        try {
            if (ex instanceof HttpRequestMethodNotSupportedException) {
                // 请求方法不支持
                LOG.warn("Request method is not supported");
                throw new BusinessException(WebRequestErrorEnum.METHOD_ERR.getCode(), ERROR_MSG);
            } else if (ex instanceof MissingPathVariableException) {
                LOG.warn("MISSING_PATHVAR" + ex.getMessage());
                // 缺少路径参数
                throw new BusinessException(WebRequestErrorEnum.MISSING_PARAM.getCode(), ERROR_MSG);
            } else if (ex instanceof MissingServletRequestParameterException) {
                // 缺少必须的请求参数
            }
            // 省略其他异常处理

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74867.html

相关文章

  • 程序员,职场上请远离这种人!

    摘要:随着微信和的不断普及,现在微信和留言也已经成为了甩锅证据的一部分,经常邮件里面大量粘贴微信聊天截图,职场上的宫心斗不比电视剧里面的差。 对有些职场人来讲,甩锅就是一种生存手段。 01.从大学打篮球说起 上大学的时候喜欢打篮球,然后我又特别喜欢抢篮板,经常是跳起来的时候没...

    khs1994 评论0 收藏0
  • 前端开发流程中一定要注意5个点!

    摘要:作为一个老前端给新人们的一些关于开发流程上的建议拒绝和设计稿没有封板就要求排期,和产品设计充分沟通。双方还是要找到平衡点确保产品质量和上线时间点的前提下,前端的开发难度和工作量是合理的。 作为一个老前端给新人们的一些关于开发流程上的建议 1. 拒绝PRD和设计稿没有封板就要求排期,和产品设计充分沟通。 前端开发经常会遇到这样的情况,项目经理莫名奇妙发了个会议邀请,然后一股脑把产品下阶段...

    王晗 评论0 收藏0
  • CDN入门了解

    摘要:维基百科的基本工作过程最简单的网络是由一台服务器和多台缓存服务器构成。用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。 前言 这段时间,在工作中遇到了一个CDN导致的图片资源加载的错误,在排查问题的过程中,发现自己对CDN的了解非常的片面,仅仅停留在它能缓存静态资源,提升访问速度的了解中。所以觉得还是非常有必要深入去了解下。 什么是CDN? CDN的全称...

    wapeyang 评论0 收藏0
  • CDN入门了解

    摘要:维基百科的基本工作过程最简单的网络是由一台服务器和多台缓存服务器构成。用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。 前言 这段时间,在工作中遇到了一个CDN导致的图片资源加载的错误,在排查问题的过程中,发现自己对CDN的了解非常的片面,仅仅停留在它能缓存静态资源,提升访问速度的了解中。所以觉得还是非常有必要深入去了解下。 什么是CDN? CDN的全称...

    Gilbertat 评论0 收藏0
  • Python源码漫游指南(一)

    摘要:源码漫游指南一作者秘塔科技算法研究员前几天发布了第五届顶级语言交互排行榜,语言继续稳坐第一把交椅,并且相比去年的排行情况,拉开了与第二名的距离去年第二名的排名得分为。包含字节码相关的底层抽象。字节码对象的实现。源文件执行结束后的清理工作。 Python源码漫游指南(一) 作者:秘塔科技算法研究员 Qian Wan 前几天IEEE Spectrum发布了第五届顶级语言交互排行榜,Pyth...

    dackel 评论0 收藏0

发表评论

0条评论

bergwhite

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<