记录vert.x的几个BUG

浪尽此生 提交于 2019-12-31 19:29:24

vert.x本身也有一些bug,用的过程当中发现了,一定会去找到根本原因,能修复的就直接修复了,修复不了的就想办法跳过。
我这边用的是3.5.2。版本有点旧了,至于新的有没有修复,我也就不去探究了,简单记录一下。

注意:修复框架的代码,一定要做好注释和笔记,以应对升级框架版本的情况。

HTTP请求方法不正确的时候状态码是404,应该是405

发布一个接口,定义的是get,你却用post调用,vertx返回的是404,准确一些应该是405。我直接说怎么修复的吧。
第一个类:io.vertx.ext.web.impl.RouteImpl
具体的方法是:

synchronized boolean matches(RoutingContextImplBase context, String mountPoint, boolean failure)

大约在230行。
这个方法是用来判断当前请求是否匹配你定义发布的接口,非常关键的方法。
有下面一行代码:

    if (!methods.isEmpty() && !methods.contains(request.method())) {
      return false;
    }

我发布了一个路由,而且定义了一些方法,但是你请求的方法并不在里面,直接返回false。外层在处理的时候,它就会认为没有找到,因此我们要做一件事情:要能够准确捕获到405的情况,并且在外层可以捕获到,把405的信息返回调用方

那怎么才能算405呢?常见的就是路径匹配上了,但方法不对,就是了。
但在vertx里面会稍微复杂一下,我修复的方式,也不一定是完全正确的,但能够满足我的需求。

我的处理逻辑如下:

  1. 定义了路径,并且路径匹配上了(有的路由可以不定义路径,仅做预处理)。
  2. 定义了方法,方法没有匹配上。
  3. 没有定义模糊匹配。

这3点目前是没有问题的,第一点也处理了子路由的情况。注意:但是可能还不够,因为它在后面又判断了一系列参数,反正我没有用到。

具体代码如下:

        if (path != null && pattern == null && !pathMatches(mountPoint, context)) {
            return false;
        }

        if (!methods.isEmpty() && !methods.contains(request.method())) {
            /**
             * update begin
             */
            if (path!=null&&pattern==null){
                //这种情况下就是,Url匹配上了,但是方法不正确,返回一个方法不允许的错误。
                String method=methods.toArray(new HttpMethod[0])[0].name();
                throw new MethodNotAllowedException(method);
            }
            /**
             * update end
             */
            return false;
        }

我调整了一下顺序,先判断路径,再判断方法;人家的是反着的。但是按照他们的顺序,你要判断405的话,判断完方法还得判断路径,所以我调整了一下。

然后自定义了一个异常,同时把应该采用的方法也放进去了(直接取了第一个),这个异常是为了让外层捕获和处理。

第二个类:io.vertx.ext.web.impl.RoutingContextImplBase
具体方法

    protected boolean iterateNext() {}

在最后面有一个catch

catch (IllegalArgumentException e) {
        if (log.isTraceEnabled()) log.trace("IllegalArgumentException thrown during iteration", e);
        // Failure in handling failure!
        unhandledFailure(400, e, route.router());
        return true;
      }

这里会捕捉到刚才的异常,判断一下,直接返回错误消息,return true就行了。

catch (Exception e) {
                /**
                 * update start
                 */
                if (e instanceof MethodNotAllowedException){
                    this.response().setStatusCode(HttpResponseStatus.METHOD_NOT_ALLOWED.code());
                    this.response().end("方法不允许,你应该用这个方法来调用:"+e.getMessage());
                    return true;
                }
                /**
                 * update end
                 */
                if (log.isTraceEnabled()) log.trace("IllegalArgumentException thrown during iteration", e);
                // Failure in handling failure!
                unhandledFailure(400, e, route.router());
                return true;
            }

总体来说还是比较简单的。

使用MySQLClient.createShared(Vertx vertx, JsonObject config)创建的mysql客户端在查询字段类型为:bit(1)的时候会出错。

跟代码的过程就不详细说了,直接说结论。
我们都知道对于mysql来讲,bit(1)可以用作布尔变量,而且驱动返回的就是Boolean,但是当大于1的时候,就会返回byte[]。

上面的方法返回的客户端是AsyncSQLClientImpl,这个客户端返回的连接对象是:
io.vertx.ext.asyncsql.impl.MySQLConnectionImpl

当然它内部有个真正的引用,是:
com.github.mauricio.async.db.mysql.MySQLConnection

罪魁祸首就是它,当它查询bit(1)的时候,返回的居然是个byte[],根本不符合人家mysql的规范。
然后vertx的Json在增加内容的时候,处理byte[]的时候,会使用BASE64做处理,本来是0和1,然后看的时候就变成了AQ==,也是非常郁闷。

当然这并不是它不能处理byte[],只不过是内存里面是这样存储byte的。
那么能不能用getBinary方法取呢,可以。这个返回byte[]数组,但是取出来你可能还得取出第一位去判断是1还是0。但没有必要,它本身就是错的。
而且仅仅用来判断状态还是可以的,但是如果传输的话,万万是不行的。

解决思路:以后别用这个了,还是用JDBC吧,已经用了,就换了,改动不大,如下:

JDBCClient.createShared(Vertx vertx, JsonObject config)

这个是没有问题的。

当然也引出了其它问题,比如用vert.x的json传输byte[]的时候,要注意一下,特别是和异构系统的数据传输交互问题。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!