是返回类似下面的业务错误码结构,

```json
{
    "rc": 10001,
    "msg": "部分商品没有库存",
    "data": {
        "out_of_stock_ids": [
            1,
            2,
            3
        ]
    }
}
```

还是抛出下面这样的自定义异常?
```python3
class BaseBusinessError(Exception):
    rc = 500
    msg = 'Unknown error'
    data = None

    def __repr__(self):
        return f'<Error {self.rc}: {self.msg}. data: {self.data}>'

    def __str__(self):
        return self.__repr__()


class ShopOutOfStockError(BaseBusinessError):
    rc = 10001
    msg = "部分商品没有库存"
    data = None

    def __init__(self, product_ids: list):
        self.data = product_ids

```

如果采用异常方案,调用方没有自定义异常类的定义怎么办?如何反序列化?是不是要共享异常的定义代码给所有调用方?要是调用方是其它语言呢?


[这篇博客]( https://www.cnblogs.com/luozhiyun/p/10251585.html) 下的这句:

> 查询方法不建议抛出 checked 异常,否则调用方在查询时将过多的 try...catch ,并且不能进行有效处理。

中的 checked 异常是什么意思?是否可以理解为查询方法不抛异常。比如,查询某个数据没有权限,直接返回空,而不是抛一个没有权限的异常。
举报· 89 次点击
登录 注册 站外分享
2 条回复  
timethinker 小成 2024-7-2 19:27:38
在 Java 中,受检(checked)异常指的是必须要用 try..catch 来调用一个可能会抛出受检异常的方法。python 中应该所有的都是非受检异常,也就是不强迫你使用 try..catch 。

言归正传,不要把异常跟传输搞混了,RPC 本质上也是通过网络传递数据,至于怎么处理这个数据,你可以参考一下 HTTP 协议,返回不同的状态码来表示协议级别的成功与否。或者不需要状态码,不管成功与否永远返回一个就像你发的那样的数据结构,然后再进一步根据数据里面的 code 再决定是否要抛出异常。
povsister 小成 2024-7-2 20:08:34
通常对于 rpc 来说,其框架已经定义过了错误,并且提供了错误的扩展(描述、details 等),就不要再把“业务错误”包装成正常响应返回了,否则你在可观测上会遇到不小麻烦。

而且,看你的设计,你在异常里,又返回了 data ,并且还描述了业务相关数据( out of stock ids ),那么你本质就不是想返回错误,而是告诉请求方你提交的哪些数据不合法。
这时候你就要反思你的设计:你究竟是想交互,还是想抛出错误?对于一个错误来说你返回的信息里包含了太多业务场景相关信息,没有通用性。应该考虑这是一次正常交互。

错误描述的扩展,应该是描述错误本身,首先,应该提供一个统一注册管理的 bizErrorCode ,这个是可观测的基础,同时应该提供 description ,这个是对错误的描述,提供一些场景、debug 信息,而且仅应该用于 localization 或者程序员调试使用。
返回顶部