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

背景

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

问题分析

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

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

前端观点: 后端代码太不健壮了, 就算前端传错了,也应该具有容错性;此外APP是有版本的,就算hotfix,用户也不必定升级,上一版本用户仍是会有问题,因此这种问题尽可能是后端来修复。服务器

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

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

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

通用异常的处理方式

http一般错误有debug

  • 4开头:客户端参数有问题,须要后端提供debug信息。理论上应该只是联调的时候会出现,可是实际上不必定(这不就打脸了吗)
  • 5开头:服务器端有错误,客户端有统一提供的异常处理
  • 2开头:业务异常,若是有UI要求,后端返回一个code码,前端根据code码,展现UI。若是没有UI要求,前端直接展现后端返回的错误消息。

为了统一异常处理,通常公司的作法都是API统一返回一套数据格式,日志

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

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

那么前端处理异常的逻辑

此次的问题就是走到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<Result> 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.cnblogs.com/stoneFang/p/10987681.html

相关文章
相关标签/搜索