在我的博客阅读本文
文章目录
2021-06-30新增了部分代码演示,请参考
2022-02-17更新,之前思路有局限,这里不推荐使用异常来处理业务上的异常,基于此认知,更推荐业务上能够约定固定的数据结构ResultDTO,能够描述业务上的异常,比如错误码等信息,”异常“的处理,更推荐是在不可预知的非义务异常上进行兜底,目前已在todo list中,准备重新设计,来补足业务上已知的异常处理方式。
1. 核心诉求
- 服务提供方异常能够被服务消费方感知
- 异常分类处理:
- 业务异常,需要返回对应的错误码,方便服务消费方进行国际化文案的提示+日志。
- 非业务异常(比如NPE),需要返回内容给到服务消费方感知。
- 拓展性&流程尽可能简单
2. 方案选择
2.1. 直接调用OnError方法,传递Status包装异常后返回
例子:
try {
}catch (Throwable t) {
// Throwable t | StreamObserver<xxx> responseObserver
responseObserver.onError(Status.UNKNOWN
.withDescription(t.getMessage())
.withCause(t)
.asRuntimeException());
}
这个方式客户端可以感知到,但是可能能够放入的信息有限,只能是一个字符串,只能在withDescription
这个参数里,如果要多个参数,可能借助一些序列化框架转化为字符串进行转换。
2.2. 借助protobuf 的 OneOf语法
protobuf文件:
message Request {
int32 number = 1;
}
message SuccessResponse {
int32 result = 1;
}
enum ErrorCode {
ABOVE_20 = 0;
BELOW_2 = 1;
}
message ErrorResponse {
int32 input = 1;
ErrorCode error_code = 2;
}
// 重点是这里,回调有两种,一个成功,一个失败
message Response {
oneof response {
SuccessResponse success_response = 1;
ErrorResponse error_response = 2;
}
}
service CalculatorService {
rpc findSquare(Request) returns (Response) {
};
}
Java代码:
@Override
public void findSquare(Request request, StreamObserver<Response> responseObserver) {
Response.Builder builder = Response.newBuilder();
try {
// 异常业务
}catch (Throwable t) {
// 有异常的话返回错误的Message类型
ErrorResponse errorResponse = ErrorResponse.newBuilder()
// 业务异常
.setInput(xxx)
// 业务错误代码
.setErrorCode(errorCode)
.build();
builder.setErrorResponse(errorResponse);
return;