URL編碼 URLEncoder 示例


2016-12-27
對字符編碼時的規則
       
       
       
               
通常如果一樣東西需要編碼,說明這樣東西並不適合傳輸。原因多種多樣,如Size過大,包含隱私數據。
對於Url來說,之所以要進行編碼,一個是 因為Url中有些字符會引起歧義。 
例如Url參數字符串中使用key=value鍵值對這樣的形式來傳參,鍵值對之間以&符號分隔,如/s?q=abc&ie=utf-8。 如果你的value字符串中包含了=或者&,那么勢必會造成接收Url的服務器解析錯誤,因此必須將引起歧義的&和=符號進行轉義,也就是對其進行編碼
另外, Url的編碼格式采用的是ASCII碼,而不是Unicode(包含中文),這也就是說你不能在Url中包含任何非ASCII字符,例如中文。否則如果客戶端瀏覽器和服務端瀏覽器支持的字符集不同的情況下,中文可能會造成問題。

編碼時的規則:
  • 【字母】字符 "a" 到 "z"、"A" 到 "Z" 和【數字】字符 "0" 到 "9" 保持不變
  • 特殊字符【.】【-】【*】【_】保持不變
  • 空格字符 【 】轉換為一個加號【+】
  • 所有其他字符都是不安全的,因此首先使用一些編碼機制將它們轉換為【一個或多個】字節,然后每個字節用一個包含 3 個字符的字符串【%xy】表示,其中 xy 為該字節的兩位十六進制表示形式。
  • 可以指定對這些字符進行解碼的編碼機制,或者如果未指定的話,則使用平台的默認編碼機制。

例如,使用 UTF-8 編碼機制,字符串【ü@】將轉換為【%C3%BC%40】,因為在 UTF-8 中,字符【ü】編碼為兩個字節【 0x C3和 0x BC】,字符【@】編碼為一個字節【0x40】。
 

解碼時的規則:
  • 將把【%xy】格式的子序列視為【一個字節】,其中 xy 為 8 位的兩位十六進制表示形式。
  • 然后,所有連續包含一個或多個這些字節序列的子字符串,將被其編碼可生成這些連續字節的字符所代替。
      
測試代碼
        
        
        
                
public class Test {
    public static void main(String[] args) throws Exception {
        String enc = "UTF-8";
        test("aA0 .-*_", enc);//編碼【aA0+.-*_】解碼【aA0 .-*_】
        test("@", enc);//編碼【%40】解碼【@】
        test("ü", enc);//編碼【%C3%BC】解碼【ü】
        test("白", enc);//編碼【%E7%99%BD】解碼【白】
        test("白""GBK");//編碼【%B0%D7】解碼【白】
    }
    /**
     * 測試編解碼
     * @param str    原始字符串
     * @param enc    對字符串進行URLEncoder和URLDecoder時使用的編碼規則
     * @throws UnsupportedEncodingException
     */
    public static void test(String str, String enc) throws UnsupportedEncodingException {
        String encode = URLEncoder.encode(str, enc);//推薦 UTF-8。如果未指定,則使用平台的默認編碼
        String decode = URLDecoder.decode(encode, enc);//編碼和解碼必須使用同一套碼表,否則解碼時可能亂碼
        System.out.println("原始字符串【" + str + "】編碼后【" + encode + "】解碼后【" + decode + "】");
        //獲取通過UTF8碼表編碼的字符串的字節數組
        byte[] bytes = str.getBytes(enc);
        System.out.println("        原始字符串對應的字節數組" + Arrays.toString(bytes));
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            //手動對【每個字節】都進行上面【類似URLEncoder】編碼規則的算法進行編碼(即使字母和數字也進行了編碼)
            sb.append(Integer.toHexString(b & 0xFF).toUpperCase() + " ");
        }
        System.out.println("        對每個字節都進行編碼【" + sb.toString().trim() + "】");
    }
    //源碼
    public static String decode(String s, String enc) throws UnsupportedEncodingException {
        boolean needToChange = false;
        int numChars = s.length();//字符數
        StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);
        int i = 0;
        if (enc.length() == 0) throw new UnsupportedEncodingException("URLDecoder: empty string enc parameter");
        char c;
        byte[] bytes = null;
        while (i < numChars) {
            c = s.charAt(i);//逐個遍歷所有字符
            switch (c) {
            case '+':
                sb.append(' ');
                i++;
                needToChange = true;
                break;
            case '%':
                try {
                    if (bytes == null) bytes = new byte[(numChars - i) / 3];// (numChars-i)/3 is an upper bound上線 for the number of remaining剩下的 bytes
                    int pos = 0;
                    while (((i + 2) < numChars) && (c == '%')) {
                        int v = Integer.parseInt(s.substring(i + 1, i + 3), 16);//16進制
                        if (v < 0) throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value");
                        bytes[pos++] = (byte) v;
                        i += 3;
                        if (i < numChars) c = s.charAt(i);
                    }
                    // A trailing, incomplete不完全的 byte encoding such as "%x" will cause an exception to be thrown
                    if ((i < numChars) && (c == '%')) throw new IllegalArgumentException("URLDecoder: Incomplete trailing escape (%) pattern");
                    sb.append(new String(bytes, 0, pos, enc));
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - " + e.getMessage());
                }
                needToChange = true;
                break;
            default:
                sb.append(c);
                i++;
                break;
            }
        }
        return (needToChange ? sb.toString() : s);
    }
}






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM