okhttp addHeader 字串中含有中文引起的Crash
阿新 • • 發佈:2019-01-04
java.lang.IllegalArgumentException
Unexpected char 0x950b at 35 in User-Agent value: Mozilla/5.0 (Linux; Android 4.4.4; 鋒尚MAX Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36
異常最終是拋在了Headers中的checkNameAndValue,OKHttp 設定請求頭時,是不支援換行和中文字元的,在新增頭時會做Header的Key和Value的檢查,如果發現非法字元則丟擲上述異常。
private void checkNameAndValue(String name, String value) { if (name == null) throw new IllegalArgumentException("name == null"); if (name.isEmpty()) throw new IllegalArgumentException("name is empty"); for (int i = 0, length = name.length(); i < length; i++) { char c = name.charAt(i);if (c <= '\u001f' || c >= '\u007f') { throw new IllegalArgumentException(String.format( "Unexpected char %#04x at %d in header name: %s", (int) c, i, name)); } } if (value == null) throw new IllegalArgumentException("value == null"); for (int i = 0, length = value.length();i < length; i++) { char c = value.charAt(i); if (c <= '\u001f' || c >= '\u007f') { throw new IllegalArgumentException(String.format( "Unexpected char %#04x at %d in %s value: %s", (int) c, i, name, value)); } } }
因為服務端要統計一些資訊,所以約定每個請求都需要上傳UA。新增UA是通過實現NetworkInterceptor 網路攔截器實現每個請求都帶有UA的,國產手機廠商會把手機型號加到UA裡,也許是為了統計吧,之前的AsyncHttp沒有這個問題,測試裝置中也並未有ua帶中文的測試機,這個問題被忽略掉,吐血…… 第一個異常是因為用了全形的空格,全形的空格Unicode碼是\u3000。
解決方案:
因為UA服務端需要做統計,所以不能直接使用Base64編碼,服務端沒有解碼邏輯需要對獲取到的UA做合法性校驗,遇到不符合條件的字元就過濾掉,過濾掉這些字元對統計應該不會有什麼影響。
private static String getValidUA(String userAgent){ StringBuffer sb = new StringBuffer(); for (int i = 0, length = userAgent.length(); i < length; i++) { char c = userAgent.charAt(i); if (!(c <= '\u001f' || c >= '\u007f')) { sb.append(c);} } return sb.toString(); }在網上看到另外兩種方案,也是可行的。
法1:檢測為不合法字元,就轉為unicode 編碼,OkHttp 中的checkNameAndValue去遍歷每個字元就不會為非法了
private static String getValidUA(String userAgent){ StringBuffer sb = new StringBuffer(); for (int i = 0, length = userAgent.length(); i < length; i++) { char c = userAgent.charAt(i); if (c <= '\u001f' || c >= '\u007f') { sb.append(String.format("\\u%04x", (int) c)); } else { sb.append(c); } } return sb.toString(); }
法2:如果發現非法字元,採用UrlEncode對其進行編碼
private String getValidUA(String userAgent){ if(TextUtils.isEmpty(userAgent)){ return "android"; } String validUA = "android"; String uaWithoutLine = userAgent.replace("\n", ""); for (int i = 0, length = uaWithoutLine.length(); i < length; i++){ char c = userAgent.charAt(i); if (c <= '\u001f' || c >= '\u007f') { try { validUA = URLEncoder.encode(uaWithoutLine, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return validUA; } } return uaWithoutLine; }