Android自帶Json庫使用引起的問題

在Andriod系統應用層開發一般json協議解析使用Gson、jackson固然還公司的fastjson庫等,Andriod其實也自帶json解析庫,集成的是apache的,在一些特定的場景用自帶庫解析也很方便。
可是,不得不說自帶庫有個坑踩進去了就會被坑的挺慘,並且很難發現到問題;算法

1、背景

咱們的項目部分模塊在http請求時涉及到對參數key value計算出md5,經過json協議數據傳輸,到了服務端再作md5的校驗,正常來講計算md5的規則雙方都作了統一保證,知足了一致性的條件。理論上,只要通訊過程數據未發生篡改,100%能保證是一致的;可是問題來了,即便中間的通訊數據數據未被篡改,雙方計算出來的md5仍是存在不匹配的情形,並且出現的問題斷斷續續,一直沒有獲得有效定位和解決。apache

18_08_39__06_07_2018.jpg

然而並無想的那樣100%md5計算相同json

2、排查路徑

2.1 分析現象

問題出現時會一直提示md5校驗失敗,說明兩邊的md5計算結果確實不同,然而發生的機率很低,低到幾乎能夠忽略不計,但只要出現問題就能穩定復現。app

2.2 定位問題

首先,很容易想到的是雙方計算規則不一樣,計算的層級不一樣,畢竟Android端對庫的依賴和服務端庫的依賴存在這差異;然而,將算法統一校準後問題並無獲得解決~spa

再來從有問題的請求json串入手分析,發現帶問題的json數據給到服務端解析後--出現json轉化的值一些些特定字符都會被去掉,那問題其實就定位到了,但這個服務端的問題嗎?畢竟它每次都會將值裏邊的某個字符給丟掉。查下json規範,http://www.rfc-editor.org/rfc/rfc4627.txt(RFC 4627)轉義符號會被看成無效字符給丟棄,說的也很清楚。調試

18_32_19__06_07_2018.jpg
很明顯編譯器也過不了這種規則,可是json數據傳輸時這串是能成立的code

那是數據獲取源頭產生的問題嗎,它是否在運行過程當中就是產生了這種string值?動態調試了一番發如今字段賦值的時候的確是沒有轉義字符的('')。很明顯了,就是在轉換成json的時候被加上轉義符了,這也很難和md5計算扯上聯繫對吧?關鍵的點來了,由於一直以來都是在最後的封裝環節把數據封裝好了數據才進行md5計算,這個思路和方案都沒有問題的(不可能提早知曉全部字段和值吧?),那就說明是使用系統json庫取值的時候出了問題,讓轉義符也參與了計算,看源碼部分。orm

//opt是JSONObject
if (opt.getClass().isPrimitive()) {
    return opt.toString();
 }

問題是定位到了,那這是很神奇的問題啊,讓咱們從源碼來看看~blog

  • Android系統自帶json庫
//org.json.JSONStringer
private void string(String value) {
        out.append("\"");
        for (int i = 0, length = value.length(); i < length; i++) {
            char c = value.charAt(i);

            /*
             * From RFC 4627, "All Unicode characters may be placed within the
             * quotation marks except for the characters that must be escaped:
             * quotation mark, reverse solidus, and the control characters
             * (U+0000 through U+001F)."
             */
            switch (c) {
                case '"':
                case '\\':
                case '/':
                    out.append('\\').append(c);//看這
                    break;

                case '\t':
                    out.append("\\t");
                    break;

                case '\b':
                    out.append("\\b");
                    break;

                case '\n':
                    out.append("\\n");
                    break;

                case '\r':
                    out.append("\\r");
                    break;

                case '\f':
                    out.append("\\f");
                    break;

                default:
                    if (c <= 0x1F) {
                        out.append(String.format("\\u%04x", (int) c));
                    } else {
                        out.append(c);
                    }
                    break;
            }

        }
        out.append("\"");
    }

其轉義時會將字符'\'插入須要轉義的前一位,下面對比Gson的解析和封裝。md5

相關文章
相關標籤/搜索