在Andriod系統應用層開發一般json協議解析使用Gson、jackson固然還公司的fastjson庫等,Andriod其實也自帶json解析庫,集成的是apache的,在一些特定的場景用自帶庫解析也很方便。
可是,不得不說自帶庫有個坑踩進去了就會被坑的挺慘,並且很難發現到問題;算法
咱們的項目部分模塊在http請求時涉及到對參數key value計算出md5,經過json協議數據傳輸,到了服務端再作md5的校驗,正常來講計算md5的規則雙方都作了統一保證,知足了一致性的條件。理論上,只要通訊過程數據未發生篡改,100%能保證是一致的;可是問題來了,即便中間的通訊數據數據未被篡改,雙方計算出來的md5仍是存在不匹配的情形,並且出現的問題斷斷續續,一直沒有獲得有效定位和解決。apache
然而並無想的那樣100%md5計算相同
json
問題出現時會一直提示md5校驗失敗,說明兩邊的md5計算結果確實不同,然而發生的機率很低,低到幾乎能夠忽略不計,但只要出現問題就能穩定復現。app
首先,很容易想到的是雙方計算規則不一樣,計算的層級不一樣,畢竟Android端對庫的依賴和服務端庫的依賴存在這差異;然而,將算法統一校準後問題並無獲得解決~spa
再來從有問題的請求json串入手分析,發現帶問題的json數據給到服務端解析後--出現json轉化的值一些些特定字符都會被去掉,那問題其實就定位到了,但這個服務端的問題嗎?畢竟它每次都會將值裏邊的某個字符給丟掉。查下json規範,http://www.rfc-editor.org/rfc/rfc4627.txt(RFC 4627)轉義符號會被看成無效字符給丟棄,說的也很清楚。調試
很明顯編譯器也過不了這種規則,可是json數據傳輸時這串是能成立的
code
那是數據獲取源頭產生的問題嗎,它是否在運行過程當中就是產生了這種string值?動態調試了一番發如今字段賦值的時候的確是沒有轉義字符的('')。很明顯了,就是在轉換成json的時候被加上轉義符了,這也很難和md5計算扯上聯繫對吧?關鍵的點來了,由於一直以來都是在最後的封裝環節把數據封裝好了數據才進行md5計算,這個思路和方案都沒有問題的(不可能提早知曉全部字段和值吧?),那就說明是使用系統json庫取值的時候出了問題,讓轉義符也參與了計算,看源碼部分。orm
//opt是JSONObject if (opt.getClass().isPrimitive()) { return opt.toString(); }
問題是定位到了,那這是很神奇的問題啊,讓咱們從源碼來看看~blog
//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