iohao / ioGame

无锁异步化、事件驱动架构设计的 java netty 网络编程框架; 轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式; 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景; 通过 ioGame 你可以很容易的搭建出一个集群无中心节点、集群自动化、分布式的网络服务器;FXGL、Unity、UE、Cocos Creator、Godot、Netty、Protobuf、webSocket、tcp、socket;java Netty 游戏服务器框架; Java Netty Game Server.
http://game.iohao.com
GNU Affero General Public License v3.0
920 stars 205 forks source link

关于AfterAction接口与MsgException异常处理相关异常的处理 #369

Closed wallacefw1987 closed 1 week ago

wallacefw1987 commented 2 months ago

你的问题 | 使用场景

假如我这里role-action中有个infonation的方法内,由于by zero的错误,导致异常被捕获,通过文档: 扩展 ActionAfter ,携带异常信息ActionAfter 文章分别介绍了大概的处理方案,而我根据这写下了如下demo:

预期值

我预设的期望是,假如爆粗了,我日志显示了error信息,返回的报文还是如下:

假如出现错误是如下:
{
    "code": 20001,
    "msg": "xxxxxxx"
}

实际值

现在的情况是在源码这里直接诶就是com.iohao.game.external.client.user.ClientUserChannel.DefaultChannelRead 中这里就没有了

Snipaste_2024-09-09_18-52-46

版本

iohao commented 2 months ago

描述不清晰,无法提供回答。下面的结构是怎么来的

假如出现错误是如下:
{
  "code": 20001,
  "msg": "xxxxxxx"
}

关于实际值的描述也没看懂,描述中的 没有了 是指什么没有了。

wallacefw1987 commented 2 months ago

描述不清晰,无法提供回答。下面的结构是怎么来的

假如出现错误是如下:
{
    "code": 20001,
    "msg": "xxxxxxx"
}

关于实际值的描述也没看懂,描述中的 没有了 是指什么没有了。

我这里client执行的过程中:

@Slf4j
public class DemoRoleClusterClient {

    public static void main(String[] args) {
        ClientUserConfigs.closeLog();

        String websocketNonVerify = "?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6OTE3ODk5NjM3MTA3MjAwLCJ1c2VybmFtZSI6IndhbGxhY2VmdzYiLCJwYXNzd29yZCI6ImVvY2xzZG9naiIsImNyZWF0ZVRpbWUiOjE3MjQ4OTYzMTAsInNlY3JldCI6Ijk4MzI3MCIsImxvZ2luVGltZSI6MTcyNTg1ODE5OX0.4Mt-xFccLxUfMZqiWvJbHGMmhuCe5YMVIpQfGgNkQ_U&&options=role&&pin=Yes";

        // 模拟请求数据
        List<InputCommandRegion> inputCommandRegions = List.of(
                new DemoClusterRegion()
        );

        // 启动模拟客户端
        new ClientRunOne()
                //todo--这里设置token
                .setWebsocketVerify(websocketNonVerify)
                .setInputCommandRegions(inputCommandRegions)
                .startup();
    }

    static class DemoClusterRegion extends AbstractInputCommandRegion {
        @Override
        public void initInputCommand() {
            // 模拟请求的主路由
            inputCommandCreate.cmd = RoleCmd.cmd;

            //整合结果没有问题
            ofCommand(RoleCmd.information).setTitle("用户信息").callback(result -> {
                String value = result.getString();
                log.info("value : {}", value);
            });

这里代码callback的lamdba还没执行就已经报下满错误了,客户短这里接收读没有,直接报错了! A4E595979D46354BD53878AF8689E7AC 因为我希望预期的情况是try...catch捕获我的异常代码如下: Snipaste_2024-09-09_21-00-17

我希望可以出现返回结果如下,返回一个报错json,code代表error code,msg:出错的内容

{
    "code": 20001,
    "msg": "xxxxxxx"
}

但是现在我结果就是这样: A4E595979D46354BD53878AF8689E7AC

iohao commented 2 months ago

返回错误码是不会执行 callback 方法的,只有 action 正常返回时才会进入 callback 方法。相关源码如下 https://github.com/iohao/ioGame/blob/b977b616a1794c69c719f24df8449a192f045abb/widget/light-client/src/main/java/com/iohao/game/external/client/user/ClientUserChannel.java#L168-L194

wallacefw1987 commented 2 months ago

因为我看这里demo的例子

返回错误码是不会执行 callback 方法的,只有 action 正常返回时才会进入 callback 方法。相关源码如下

https://github.com/iohao/ioGame/blob/b977b616a1794c69c719f24df8449a192f045abb/widget/light-client/src/main/java/com/iohao/game/external/client/user/ClientUserChannel.java#L168-L194

所以我可以理解为我要重写游戏客户端ClientUserChannel#read方法 -- 读取channel中的responseStatus去判断,实现一个类似于requestCommand.getCallback()).ifPresent(callback -> callback.callback(commandResult) 的结果出来,是这个意思对吗?

iohao commented 2 months ago

是的

wallacefw1987 commented 2 months ago

是的

我这里用了简单捕获异常的方法,暂时解决 Snipaste_2024-09-10_01-01-37

iohao commented 2 months ago

看你的打印,MsgRoleResp 是一个通用的包装响应吗;会有很多 action 的返回值使用该对象吗。

wallacefw1987 commented 2 months ago

看你的打印,MsgRoleResp 是一个通用的包装响应吗;会有很多 action 的返回值使用该对象吗。

对,在role-action就是通用响应包,里面属性:code、message、data。 请教:游戏server 和 client之间交互,也是有这样一个通用响应对象交互把?如果出错有error code辨识执行正确与否

iohao commented 2 months ago

看你的打印,MsgRoleResp 是一个通用的包装响应吗;会有很多 action 的返回值使用该对象吗。

对,在role-action就是通用响应包,里面属性:code、message、data。 请教:游戏server 和 client之间交互,也是有这样一个通用响应对象交互把?如果出错有error code辨识执行正确与否

ExternalMessage 已经具备这样的职能了,不建议开发者使用 MsgRoleResp 这种方式来做通用的包装响应。

see 对外服的协议说明 (yuque.com)

// 对外服数据协议
message ExternalMessage {
  // 响应码: 0:成功, 其他为有错误
  sint32 responseStatus = 4;
  // 验证信息(错误消息、异常消息),通常情况下 responseStatus == -1001 时, 会有值
  string validMsg = 5;
  // 业务请求数据
  bytes data = 6;

  ... 省略部分代码
}

建议使用目前所推荐的方式,即 action 返回具体的业务对象。这么做有如下优势

  1. 生成 javadoc 时,可以知道 action 的具体返回类型,而返回通用包装响应无法做到。
  2. 游戏对接文档生成 (yuque.com)时,可以知道 action 的具体返回类型,而返回通用包装响应无法做到。
  3. 将来使用SDK TypeScript 代码生成 (yuque.com)时,可以知道 action 的具体返回类型,而返回通用包装响应无法做到。

总的来说,MsgRoleResp 通用包装响应是不建议使用的,这是因为:

  1. 隐藏了太多的关键信息,不利于联调,会增加沟通成本、维护成本及开发成本;
  2. 会让业务代码增加不必要的理解成本,原来只需要返回一个具体的业务对象即可,而现在还需要做一层包装。
  3. 无法使用断言 + 异常机制 = 清晰简洁的代码 (yuque.com)等相关机制。我们建议在业务代码中使用断言机制,这可以让我们的业务代码变得更加的简洁;当触发断言时,框架会将相关错误码存放到 ExternalMessage 中,具体请阅读异常码会放在什么地方相关小节。
wallacefw1987 commented 2 months ago

看你的打印,MsgRoleResp 是一个通用的包装响应吗;会有很多 action 的返回值使用该对象吗。

对,在role-action就是通用响应包,里面属性:code、message、data。 请教:游戏server 和 client之间交互,也是有这样一个通用响应对象交互把?如果出错有error code辨识执行正确与否

ExternalMessage 已经具备这样的职能了,不建议开发者使用 MsgRoleResp 这种方式来做通用的包装响应。

see 对外服的协议说明 (yuque.com)

// 对外服数据协议
message ExternalMessage {
  // 响应码: 0:成功, 其他为有错误
  sint32 responseStatus = 4;
  // 验证信息(错误消息、异常消息),通常情况下 responseStatus == -1001 时, 会有值
  string validMsg = 5;
  // 业务请求数据
  bytes data = 6;

  ... 省略部分代码
}

建议使用目前所推荐的方式,即 action 返回具体的业务对象。这么做有如下优势

  1. 生成 javadoc 时,可以知道 action 的具体返回类型,而返回通用包装响应无法做到。
  2. 游戏对接文档生成 (yuque.com)时,可以知道 action 的具体返回类型,而返回通用包装响应无法做到。
  3. 将来使用SDK TypeScript 代码生成 (yuque.com)时,可以知道 action 的具体返回类型,而返回通用包装响应无法做到。

总的来说,MsgRoleResp 通用包装响应是不建议使用的,这是因为:

  1. 隐藏了太多的关键信息,不利于联调,会增加沟通成本、维护成本及开发成本;
  2. 会让业务代码增加不必要的理解成本,原来只需要返回一个具体的业务对象即可,而现在还需要做一层包装。
  3. 无法使用断言 + 异常机制 = 清晰简洁的代码 (yuque.com)等相关机制。我们建议在业务代码中使用断言机制,这可以让我们的业务代码变得更加的简洁;当触发断言时,框架会将相关错误码存放到 ExternalMessage 中,具体请阅读异常码会放在什么地方相关小节。

读了这里:游戏对接文档生成 (yuque.com)时,可以知道 action 的具体返回类型msgRoleResp,我需要在外服的编码与解码当中,把数据转化成ExternalMessage对象,当中传入参数和转出参数(由action -- > 外服是援用msgRoleResp这个没问题!),但需要在外服转化为ExternalMessage对象中的data(byte[] 类型)! 同样滴,客户端 --> 外服需要把RequestParam转化为ExternalMessage对象,当中的data就是action内method的入参! 应该是这么理解把。

iohao commented 2 months ago

没明白你的描述,你是想自定义统一的交互协议吗,框架支持自定义 ExternalMessage,可以阅读对外服的协议说明 (yuque.com) 的相关小节。