URLDecoder對參數進行解碼時候,代碼如:
URLDecoder.decode(param,"utf-8");
有時候會出現類似如下的錯誤:
URLDecoder異常Illegal hex characters in escape (%)
這是因為傳參有一些特殊字符,比如%號或者說+號,導致不能解析,報錯
如果收到的HTTP請求參數(URL中的GET請求)中有一個字符串,是中文,比如“10%是黃段子”,服務器段使用URLDecoder.decode就會出現此異常。URL只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其他文字和符號。如果內容中存在中文,必須要進行編解碼。“10%是黃段子”轉碼過后是“10%25%E6%98%AF%E9%BB%84%E6%AE%B5%E5%AD%90%”被用來作為轉義字符使用。
上面的字符串中'%'是一個中文字符'是',而轉換的實現是將%后面的兩個字符一起轉為一個16進制數。拿"%是"來轉換數字,肯定會有NumberFormatException異常。
類似的如果請求字符串中有'+',也會有問題。因為'+'被當做空格使用了。一個解決辦法就是將%替換為%25。
解決方法是:
1 public static String replacer(StringBuffer outBuffer) { 2 String data = outBuffer.toString(); 3 try { 4 data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25"); 5 data = data.replaceAll("\\+", "%2B"); 6 data = URLDecoder.decode(data, "utf-8"); 7 } catch (Exception e) { 8 e.printStackTrace(); 9 } 10 return data; 11 }
這里使用了一個特殊正則表達式:零寬負向先行斷言(zero-widthnegative lookahead assertion),模式為(?!pattern),代表字符串中的一個位置,緊接該位置之后的字符序列不能匹配pattern。%(?![0-9a-fA-F]{2})意思是'%'開始,但是后面兩個字符不是數字,也不是字母。
或者使用POST請求,將參數參加到body中而不是請求url拼接
URLDecoder源碼:
1 public static String decode(String s, String enc) 2 throws UnsupportedEncodingException{ 3 4 boolean needToChange = false; 5 int numChars = s.length(); 6 StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars); 7 int i = 0; 8 9 if (enc.length() == 0) { 10 throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter"); 11 } 12 13 char c; 14 byte[] bytes = null; 15 while (i < numChars) { 16 c = s.charAt(i); 17 switch (c) { 18 case '+': 19 sb.append(' '); 20 i++; 21 needToChange = true; 22 break; 23 case '%': 24 /* 25 * Starting with this instance of %, process all 26 * consecutive substrings of the form %xy. Each 27 * substring %xy will yield a byte. Convert all 28 * consecutive bytes obtained this way to whatever 29 * character(s) they represent in the provided 30 * encoding. 31 */ 32 33 try { 34 35 // (numChars-i)/3 is an upper bound for the number 36 // of remaining bytes 37 if (bytes == null) 38 bytes = new byte[(numChars-i)/3]; 39 int pos = 0; 40 41 while ( ((i+2) < numChars) && 42 (c=='%')) { 43 int v = Integer.parseInt(s.substring(i+1,i+3),16); 44 if (v < 0) 45 throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value"); 46 bytes[pos++] = (byte) v; 47 i+= 3; 48 if (i < numChars) 49 c = s.charAt(i); 50 } 51 52 // A trailing, incomplete byte encoding such as 53 // "%x" will cause an exception to be thrown 54 55 if ((i < numChars) && (c=='%')) 56 throw new IllegalArgumentException( 57 "URLDecoder: Incomplete trailing escape (%) pattern"); 58 59 sb.append(new String(bytes, 0, pos, enc)); 60 } catch (NumberFormatException e) { 61 throw new IllegalArgumentException( 62 "URLDecoder: Illegal hex characters in escape (%) pattern - " 63 + e.getMessage()); 64 } 65 needToChange = true; 66 break; 67 default: 68 sb.append(c); 69 i++; 70 break; 71 } 72 } 73 74 return (needToChange? sb.toString() : s); 75 }