記錄vert.x的幾個BUG

前言

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[]的時候,要注意一下,特別是和異構系統的數據傳輸交互問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章