探究Web經常使用編碼

今天呢,小編決定帶着6個方面一路探究Web編碼。javascript

一、問:爲啥要編碼?

答:計算機存儲信息的最小單位是1字節(bit),然而一個字節最多能表示0-255個符號,可是人類天然語言中的符號又那麼多,像漢語、韓語、日語等一個字節怎麼能表示的過來,因此必需要有一個新的結構字符來編碼。java

二、常見的編碼格式有哪些?

A、ASCII碼
總共128個,使用一個字節的低7位表示,0-31是控制字符如:換行、回車、刪除等;32-126是打印字符,能夠經過鍵盤的輸入打印出來。
如:數據庫

System.err.println('A'+32);
char abcd = 'A' +32;
System.err.println(abcd);

獲得:windows

探究Web經常使用編碼

B、ISO-8859-1
ISO提到這個名字我就想到了,食品安全上的那個。ISO組織在ASCII碼的基礎上利用單個字節的全部位定製了一系列標準擴展ASCII編碼,ISO-8859-1仍然是單字節編碼,總共256個字符。咱們下面提到的瀏覽器編碼規則就是依據於此。
C、GB2312
全稱《信息技術中文編碼字符串》,它採用雙字節編碼,範圍是A1-F7,其中A1-A9是符號區有682個符號;B0-F7是漢字區包含6763個漢字。
D、GBK
全稱《漢字內碼擴展規範》是國家技術監督局爲windows95定製的新的內碼規範,是擴展GB2312用的,由於漢字不止6763個,你懂的。加入了更多的漢字,編碼範圍是8140-FEFE,總共23940個這下夠用了。
E、UTF-16
UTF-16定義了Unicode字符在計算機中的存取方法,UTF-16使用兩個字節表示Unicode的轉化格式,是固定長度的表示方式,不管什麼字符UTF-16都用兩個字節表示,兩個字節是16位,因此叫UTF-16你又懂得。
F、UTF-8
互聯網的普及,市面上所見之處都是UTF-8,是互聯網上使用最普遍的Unicode實現方式(下面降Unicode)。上面所講UTF-16表示起來很方便了,可是存儲上是否是多佔用了空間,由於不管你用不用都給你2個字節。而UTF-8編碼規則以下:瀏覽器

①對於單字節符號,字節的第一位設爲0,後7位是這個符號的Unicode碼。所以UTF-8包含ASCII碼。
②對於n位字節的符號(n>1),第一個字節都設爲1,第n+1位設爲0,後面字節的前兩位一概設爲10。其他的都爲這個符號的Unicode碼。
安全

G、Unicode
就小編知道的編碼格式大概有30種左右吧,像阿拉伯文(ASMO 708)、俄語 - 西里爾文(DOS)、日文(Shift-JIS)、中國 - 簡體中文(GB2312)、繁體中文(Big5)、Unicode、Unicode (Big-Endian)、中歐(Windows)、西里爾文(KOI8-R)、 西里爾文(KOI8-U)、 阿拉伯文(ISO)、希伯來文(ISO-Visual)、希伯來文(ISO-Logical)、日文(JIS)、韓文(ISO)、日文(EUC)、韓文(EUC)、簡體中文(HZ)、Unicode (UTF-7)、Unicode (UTF-8)等。
若是有一種編碼將世界上全部符號都歸入其中,每個符號都給予一個獨一無二的編碼,那麼亂碼問題就不會有了對吧,這就是Unicode。Unicode是一個龐大的集合,能夠容納百萬計符號。服務器

三、瀏覽器界面編碼格式

在瀏覽器調試界面,咱們選擇控制檯,而後輸入document.charset便可獲取當前界面的編碼規則。咱們能夠看到三種瀏覽器:谷歌、火狐、IE的編碼均爲utf-8,由於是互聯網上使用最普遍的Unicode實現方式:網絡

探究Web經常使用編碼

四、瀏覽器URL編碼方式

客戶端想服務器發送請求四種狀況:
一、表單post提交;
二、表單get提交;
三、頁面連接;
四、URL方式直接訪問
而URL包含中文無非有兩種狀況:
一、url路徑包含中文即
https://abcd/測試/publish
這種類型的,從這麼多年的上網經驗來說,我沒見過這種路徑。
二、url參數包含中文,這問題比較常見。
咱們看到當URl包含中文參數時,瀏覽器作了轉碼。
探究Web經常使用編碼
這一點上,分兩種狀況IE和非IE,由於IE用的是GBK轉碼,非IE用的是Utf-8轉碼,而咱們在windows系統上查詢默認的編碼就是GBK。
探究Web經常使用編碼
所以,你會發現IE瀏覽器好像對中文沒有作處理通常
探究Web經常使用編碼app

在URL進行參數傳遞的時候,要處理處理中文參數那麼這裏就要注意了,咱們有三種解決方案(javascript轉碼、配置filter過濾器、修改中間件server.xml),這裏咱們考慮最簡單的js轉碼方案。用戶從瀏覽器發起一個Http請求,存在編碼的地方是URL、Cookie、Parameter。服務器端接受到Http請求後要解析Http,其中URL、Cookie和Post表單參數須要解碼、服務器端還可能讀取數據庫數據或者文本文件,均可能存在編碼問題。當servlet處理完全部請求數據後,再將這些數據編碼經過socket發送到用戶請求的瀏覽器裏,經瀏覽器解析成文本。
瀏覽器編碼URL是將非ASCII字符按照某種編碼格式,編碼成16進制的數字後將16進制數字表示的字節前加上%。這個過程就不太美了,由於不一樣瀏覽器編碼方式可能還不同,那服務端怎麼解,因此咱們在應用中儘可能避免URl使用非ASCII字符。
問:要是避免不了怎麼辦呢?socket

答:咱們經過下面的例子一塊兒探究
假如咱們在地址欄中有這樣的參數地址
http://localhost:2345/redant/test.action?name=測試
咱們寫一個測試的小demo

<a onclick="test_decode(1)">測試轉碼問題1</a><br/>
<a onclick="test_decode(2)">測試轉碼問題2</a><br/>
<a onclick="test_decode(3)">測試轉碼問題3</a><br/>
<a onclick="test_decode(4)">測試轉碼問題4</a>
<script>
    function test_decode(num){
        var url = "";
        switch (num) {
        case 1:
            url = "localhost:2345/redant/test.action?name=測試";
            break;
        case 2:
            url = "localhost:2345/redant/test.action?name=測試";
            url = encodeURI(url);
            break;
        case 3:
            url = "localhost:2345/redant/test.action?name=測試";
            url = encodeURI(encodeURI(url));
            break;
        default:
            var name = 「測試」;
            name = encodeURIComponent(encodeURIComponent(name));
            url = "localhost:2345/redant/test.action?name="+name;
            break;
        }
        alert(url);
        $.post(url);
    }
</script>

A、在URL中直接傳遞漢字參數,IE瀏覽器在java後臺獲得的關於「測試」的編碼是:

探究Web經常使用編碼

但請求的URL並未將測試進行轉碼。
火狐瀏覽器在java後臺獲得的關於「測試」的編碼是:

探究Web經常使用編碼

谷歌瀏覽器在URL請求時,已經轉碼:%E6%B5%8B%E8%AF%95,
但在java後臺獲得關於「測試」的編碼和火狐同樣:

探究Web經常使用編碼

也就是說火狐與谷歌在URL傳輸中文字符時會進行了轉碼,可是轉碼後又被瀏覽器再次處理了。IE瀏覽器處理中文字符,不會自動轉碼,但任然會被瀏覽器處理,也就是說那麼咱們拿url = "localhost:2345/redant/test.action?name=%E6%B5%8B%E8%AF%95";以後,三種瀏覽器的編碼解碼規則就一致了。
問:那麼怎麼實現,三種瀏覽器編碼規則一致呢?
答:使用【encodeURI】進行轉碼,利用encodeURI對中文URL參數進行編碼時,「測試」會轉爲「%E6%B5%8B%E8%AF%95」,但瀏覽器機制會認爲」%」是一個轉義字符,瀏覽器會把地址URL中的傳遞的已轉換的參數」%」與」%」之間的轉義字符利用自己機制處理一遍後再傳遞給後臺因此咱們使用encodeURI二次轉碼。
問:那麼咱們用encodeURI把中文字符二次轉碼保護起來,是否是就能夠了呢?
答:通過encodeURI轉碼以後,咱們能夠看到,在IE、谷歌、火狐「測試」的中文轉碼居然一致了:
探究Web經常使用編碼

在 java後臺獲得的關於「測試」的編碼,三種瀏覽器居然也一致了:

探究Web經常使用編碼

小編看到網絡上有好多例子說:在java後臺經過
java.net.URLDecoder.decode(name, "Utf-8");
就能夠解析「測試」了。
然而小編獲得的倒是:
探究Web經常使用編碼

小編懵逼的再問:這究竟是什麼編碼?
java.net.URLDecoder.decode(name, "Utf-8");
探究Web經常使用編碼
java.net.URLDecoder.decode(name, "GBK");
探究Web經常使用編碼

java.net.URLDecoder.decode(name, "ISO-8859-1");
探究Web經常使用編碼

java.net.URLDecoder.decode(name, "GB2312");
探究Web經常使用編碼

java.net.URLDecoder.decode(name, "UTF-16");
探究Web經常使用編碼

java到底該怎麼解析這個編碼,等等爲啥會帶有」/」,那去掉以後呢?
探究Web經常使用編碼
String[] str = name.split("/");
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str.length; i++) {
sb.append(str[i]);
}
System.err.println(sb);
System.err.println(java.net.URLDecoder.decode(sb.toString(), "utf-8"));
終於如願以償了
探究Web經常使用編碼
【encodeURI()與encodeURIComponent()】效果同樣。也是不得已而爲之的一種方法。
【TODO】
果真如此,小編留下一個待測試的地方:就是不一樣的瀏覽器,不一樣的系統,是否均可以使用這個方法。
問:那麼爲何會出現」/」呢?小編不得而知。

五、常見編碼問題?

上面咱們看到,編碼若是解析失敗,會出現
①一個漢字變成兩個亂碼字符
探究Web經常使用編碼
這種狀況是由於,字符串在解碼時,所使用的字符集與編碼的字符集不一致致使的,例如用GBK編碼用ISO-8859-1解碼,一個漢字變成了兩個亂碼字符。
②一個漢字變成兩個問號
探究Web經常使用編碼
這狀況就複雜了,多是中文通過屢次編碼形成的,出現這狀況你就要仔細看中間編碼環節,而後找出編碼錯誤的地方。例如:一個漢字拿GBK編碼,而後用ISO-8859-1解碼,發現不對,而後再拿GBK編碼,最後再拿GBK解碼的過程。
③一個漢字變成一個問號
將中文和中文符號通過不支持中文的ISO-8859-1編碼後,全部字符變成」?」,這是由於ISO-8859-1進行編碼是遇到不在碼值範圍內的字符統一用3f表示,所以都變成了」?」。例如:一個漢字拿ISO-8859-1編碼,再拿ISO-8859-1解碼的過程。
④咱們跨網站推送數據的時候,有時候用
String name = request.getParameter(「name」);
而後
Name = new String(name.getBytes(「ISO-8859-1」, 「GBK」));
居然獲得了正確的中文字符,這是怎麼回事?
其實一般是這樣的,咱們將漢字用GBK編碼以後,而後用ISO-8859-1解碼獲得的固然是咱們第一種所提到的那樣,而後既然不行那我再拿ISO-8859-1編碼回去,用GBK解碼。這就是那個過程。
有人會問了,爲啥不直接用GBK解碼,而是中間走一下ISO-8859-1呢?
答:由於ISO-8859-1是大多數瀏覽器的默認字符集,還有一些中間件的默認編碼也是。小編聯想到,encodeURI()它採用的是UTF-8格式輸出編碼後的字符串。也就是說,咱們能夠在瀏覽器中只進行一次轉碼就好。

url = "localhost:2345/redant/test.action?name=測試";
        url =encodeURI(url);

        咱們在後臺按照utf-8來轉就行了,即
        name = new String(name.getBytes("ISO-8859-1"),"UTF-8"); 
        固然若是編碼中有多餘的「/」,要處理掉。

六、問:Java中那些場景須要編碼?

答:兩種①I/O流中,須要指定charset。②內存操做,也就是項目運行的過程當中。

相關文章
相關標籤/搜索