zoukankan      html  css  js  c++  java
  • 对错误码的设计思考

    本文从工作中的具体实践出发,介绍自己对错误码的一些设计思考。下面将从问题背景、需求分析、设计实践这三个方面来分别阐述。

    问题背景

    抛开具体的业务处理逻辑,这个问题可以抽象为两种模式:

    报文头和报文体一致模式

    这种模式,是由前端往后台发送请求得到响应,由前端负责封包解包。这里的报头和报体具有相同的数据组织格式和逻辑层级,其逻辑一致性由业务服务来保证,具体体现如下:

    • 如果报头中的响应码出错,那报头的响应信息包含错误描述信息,报文体为空
    • 如果报头中的响应码正确,那报头的响应信息为空,报文体是正确的业务数据,且数据格式与报头一致。

    报文头和报文体不一致的模式

    这种模式,常见于在现有服务中新增一个中转服务,专门用来对接第三方服务。由前端负责对接数据的拆包和解包,中转后台服务只处理网络层的收发逻辑,不关心具体数据内容。
    由于第三方服务和中转服务都存在错误可能,因此,前端如何解析响应就需要好好设计。

    需求分析

    从使用者的角度来看,期望能够从请求响应获取以下三个接口:

    1. 该响应是成功还是失败?
    2. 如果失败,失败的错误码是多少?
    3. 如果失败,失败的错误描述信息是什么?

    使用者使用接口1来进行业务分支判断。一般来说,成功则显示响应数据,失败则通过接口2接口3来提示错误信息。其中,错误码是便于开发定位原因,错误信息是便于最终用户知晓错误情况。

    设计实践

    这里以接入第三方服务返回json格式的响应数据来举例:一般格式如下:

    {   // 响应成功
        code: 0,
        msg: "",
        data: [XXX]
    }
    
    {   // 响应失败
        code : 1000,
        msg: "XXX"
        data:{}
    }
    
    

    通过前面的分析以及具体实践,在与同事讨论中,对于接口2存在的必要性上有分歧。为什么呢?因为在现有系统中,报文头和报文体一致模式和不一致模式都存在,且都存在错误的情况,在提示用户时,在是否需要显示错误码这一点上,产品和开发意见有差异。

    • 对于报文和报体数据一致的场景,接口2的数据来源唯一,且可以保证准确一致。
    • 对于不一致的场景,接口2的数据来源有多种,具体有以下三种情况:
      • 中转层的错误码和错误信息
      • 第三方服务返回正常,但业务错误
      • 第三方服务返回异常,这里可能有:格式错误、无期望的字段等

    对于后者来说,错误信息来源也存在上述问题。按照单一职责的原则来设计,会是这样:

    struct ErrorInfo
    {
        int nErrCode;
        string nErrMsg;
    }
    
    struct ErrorInfo m_ProxyLayer;   // 中转层错误信息
    struct ErrorInfo m_ThirdLayer;    // 第三方服务层的错误信息
    bool bParseFlag;                        // 解析json是否成功
    bool bExpectField;                     // 期望字段是否存在
    
    

    由于在不同层级的错误不会同时发生,且错误码有优先级别,照此设计可使得职责清晰,缺点在于有多种设置错误方式,且在获取错误码和错误信息时,要依据错误码的优先级来处理。

    个人看法,在该场景下,有两种妥协方案,在违反单一职责原则的前提下,提供更好的封装和使用。

    方案一:在前端响应时,使用如下数据接口来保存错误信息:

    struct ErrorInfo
    {
        int nErrCode;
        string nErrMsg;
        
        void setErrorInfo(int nErrorCode, const string& strErrMsg)
        {
            this->nErrCode = nErrorCode;
            this->strErrMsg = strErrMsg;
        }
       
        bool IsRspRight(){
            return 0 != nErrCode;
        }
        
        int GetErrCode(){return nErrCode;}
        const string&  GetErrMsg(){return nErrMsg;}const
    }
    
    

    使用单一错误码以及错误信息来保存不同层级的错误信息,与上述职责分离的方案相比,设置和获取错误使用统一接口,简单直接。因为不同层级的错误不会同时发生,即使出现相同的错误码,也只会返回优先级最高的错误码以及错误信息。该方案的缺点在于复用错误码以及错误信息,上层不能依据错误信息做后续的业务判断,因为它的含义已经不再单一。

    方案二:在中转层处理,针对第三方服务的指令,提供指令适配器,将其转换为前端可统一解包的格式。好处在前端可按照之前封包解包逻辑进行处理,无需关系后端对接类型,按照中转层提供的接口传参即可。缺点在于中转层承担对接第三方服务的全部工作以及增加指令适配工作,一旦出现异常,所有依赖该中转层的指令都会失败

    小结

    针对以上场景,提出了职责分离和职责复用两种处理方式,在此抛砖引玉,大家有什么其他想法,可以在评论区一起讨论。

  • 相关阅读:
    Atitit 人脸识别 眼睛形态 attilax总结
    Atitit 手机号码选号 规范 流程 attilax总结 v2 r99.docx
    atitit 板块分类 上市公司 龙头企业公司 列表 attilax总结.docx
    Atititi atiitt eam pam资产管理 购物表去年.xlsx
    使用cmd查看电脑连接过的wifi密码(一)
    常见十大web攻击手段 悟寰轩
    常见web攻击方式 悟寰轩
    【MYSQL数据库】MYSQL学习笔记mysql分区基本操作 悟寰轩
    Filter及FilterChain的使用详解 悟寰轩
    启动tomcat spring初始化两次问题(eg:@PostConstruct) 悟寰轩
  • 原文地址:https://www.cnblogs.com/cherishui/p/13246640.html
Copyright © 2011-2022 走看看