dubbo icon indicating copy to clipboard operation
dubbo copied to clipboard

原生grpc迁移至dubbo tri协议问题汇总

Open yl-yue opened this issue 4 years ago • 12 comments

tri协议,中文异常乱码

Filter中抛出错误:

throw new BusinessException("错误的token");

得到结果:中文乱码

{
  "error": "13 INTERNAL: Exception in invoker chain :???token"
}

tri协议,在异常中加入无意义内容(Exception in invoker chain :),导致前端不方便提示异常

public abstract class AbstractServerStream extends AbstractStream implements Stream {
    public void execute(Runnable runnable) {
        try {
            super.execute(() -> {
                try {
                    runnable.run();
                } catch (Throwable t) {
                    LOGGER.error("Exception processing triple message", t);
                    transportError(GrpcStatus.fromCode(GrpcStatus.Code.INTERNAL)
                        .withDescription("Exception in invoker chain :" + t.getMessage())
                        .withCause(t));
                }
            });
        } catch (RejectedExecutionException e) {
            LOGGER.error("Provider's thread pool is full", e);
            transportError(GrpcStatus.fromCode(GrpcStatus.Code.RESOURCE_EXHAUSTED)
                .withDescription("Provider's thread pool is full"));
        } catch (Throwable t) {
            LOGGER.error("Provider submit request to thread pool error ", t);
            transportError(GrpcStatus.fromCode(GrpcStatus.Code.INTERNAL)
                .withCause(t)
                .withDescription("Provider's error"));
        }
    }
}

yl-yue avatar Dec 02 '21 03:12 yl-yue

@yl-yue Only RpcException can be thrown in the filter. Please provide an example of garbled characters. I think the second problem needs to be fixed.

CrazyHZM avatar Dec 03 '21 07:12 CrazyHZM

@yl-yue

  • tri 协议由于使用了 pb 序列化,对异常的序列化支持不好,同时对于异常使用了 http2的 header 进行传输,header 的大小有限制,不能够将异常进行序列化放入 header 中,故不支持完整的异常重放。
  • 由于 http2 header 的限制,内容只支持 AsciiString,对于其他编码建议进行 base64后放入 header
  • 如果想实现上述功能,建议参考 #8363

EarthChen avatar Dec 03 '21 10:12 EarthChen

@CrazyHZM

异常中添加前置内容不属于 bug,只为定位问题,不应该做为业务异常处理或显示

EarthChen avatar Dec 03 '21 10:12 EarthChen

异常中添加前置内容不属于 bug,只为定位问题,不应该做为业务异常处理或显示

This seems to throw an exception only when the behavior in the framework does not meet expectations. If this is the case, there is no problem here.

@EarthChen Can you add a document about the above-mentioned custom exception handling to facilitate subsequent dissemination?

CrazyHZM avatar Dec 03 '21 10:12 CrazyHZM

异常中添加前置内容不属于 bug,只为定位问题,不应该做为业务异常处理或显示

This seems to throw an exception only when the behavior in the framework does not meet expectations. If this is the case, there is no problem here.

@EarthChen Can you add a document about the above-mentioned custom exception handling to facilitate subsequent dissemination?

ok,I'll do that in the near future.

EarthChen avatar Dec 03 '21 10:12 EarthChen

@yl-yue Only RpcException can be thrown in the filter. Please provide an example of garbled characters. I think the second problem needs to be fixed.

filter throw exception:

@Activate(group = CommonConstants.PROVIDER)
public class TokenFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation inv) {
        throw new RpcException("错误的token");
    }

}

result:

{
  "error": "13 INTERNAL: Exception in invoker chain :???token"
}

Whether a Filter throw Exception or another throw exception, any message containing Chinese will be interpreted as garbled(?)

yl-yue avatar Dec 06 '21 02:12 yl-yue

@yl-yue

  • tri 协议由于使用了 pb 序列化,对异常的序列化支持不好,同时对于异常使用了 http2的 header 进行传输,header 的大小有限制,不能够将异常进行序列化放入 header 中,故不支持完整的异常重放。
  • 由于 http2 header 的限制,内容只支持 AsciiString,对于其他编码建议进行 base64后放入 header
  • 如果想实现上述功能,建议参考 [Dubbo 3.0.1] use triple protocol cant return real exception #8363

回复与新疑惑

  • 测试了 #8363 issues中提供的demo,最终的结果只是把13 INTERNAL换成了2 UNKNOWN,不过Exception in invoker chain :这串dubbo定义的前缀没了,但中文乱码任然存在。
  • 关于是2 UNKNOWN还是13 INTERNAL,更适合携带业务异常,或许dubbo可以从规范入手,做个规约说明。
  • 如果中文需要经过base64编码,这样对前端调试解析并不友好,意味着需要base64解码。

更多想法

站在我现在的角度,其实我只粗浅的觉得,dubbo tri协议最大的亮点是,不需要写下面这两行糟糕的代码:

responseObserver.onNext();
responseObserver.onCompleted();

那么是否可以考虑,dubbo tri协议是对grpc协议的缺陷或不优雅进行补足,并做增强,而不是改变,导致不能平滑迁移(只改controller层)

yl-yue avatar Dec 06 '21 03:12 yl-yue

如果中文需要经过base64编码,这样对前端调试解析并不友好,意味着需要base64解码。

  • base64是因为grpc header 规定了-bin 的都要 base64,当然你可以 url encode,只不过 base64兼容更广

dubbo定义的前缀没了,但中文乱码任然存在。

  • 乱码这个问题,将在下个版本修复它

关于是2 UNKNOWN还是13 INTERNAL,更适合携带业务异常,或许dubbo可以从规范入手,做个规约说明

  • grpc 除了框架异常,其他均是 unknown,所以这里为了保持一致
  • 总得来说,如果需要业务异常进行处理,建议增加 attach 使用 filter 在两端进行异常转换,不要使用 grpc-message

dubbo tri协议是对grpc协议的缺陷或不优雅进行补足,并做增强,而不是改变,导致不能平滑迁移(只改controller层)

  • 对于 unary 方法,dubbo 中不写onNextonCompleted是为了兼容 dubbo2,并不是为了兼容 grpc 的写法。
  • tri 和 grpc 的兼容只限于互通

EarthChen avatar Dec 06 '21 03:12 EarthChen

@EarthChen 感谢解答,谢谢!

问题一:tri协议,中文异常乱码

答案:会在下个版本中得到解决

问题二:tri协议,在异常中加入无意义内容(Exception in invoker chain :),导致前端不方便提示异常

  • 答案?:需要将13 INTERNAL异常,转换为2 UNKNOWN异常,间接解决?
  • 答案?:会在下个版本中得到解决,移除Exception in invoker chain :内容(或可配置开关)

那么问题二的答案是?

总得来说,如果需要业务异常进行处理,建议增加 attach 使用 filter 在两端进行异常转换,不要使用 grpc-message

  • 主要的问题在于我们的前端web与app也是采用的grpc通信,之所以使用 grpc-message,也是需要向用户提示,如:密码错误,之类的业务提示。
  • 同时我们后端还有异构语言,用 filter 添加 attach 的方式,显得过于复杂了。

yl-yue avatar Dec 06 '21 04:12 yl-yue

@yl-yue 问题2:

  • 框架内的异常,可能含有前置信息,不应该做为业务使用,当发生其他异常时均使用 unknown 抛出
  • 中文乱码问题会在下个版本解决,如果想实现你的需求,使用 unknown 抛出即可

EarthChen avatar Dec 06 '21 04:12 EarthChen

@yl-yue 提了个 pr 修复乱码问题,你可以尝试使用这个 pr 的代码测试一下

EarthChen avatar Dec 10 '21 09:12 EarthChen

同样碰到乱码问题,provider抛出了异常,异常内容带有中文,consumer打印异常输出的中文是???? <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> 3.3.5 application.yml配置 dubbo: protocol: name: tri serialization: hessian2

rongmome avatar Oct 20 '25 08:10 rongmome