您好,登錄后才能下訂單哦!
今天呢,小編決定帶著6個(gè)方面一路探究Web編碼。
答:計(jì)算機(jī)存儲(chǔ)信息的最小單位是1字節(jié)(bit),然而一個(gè)字節(jié)最多能表示0-255個(gè)符號(hào),但是人類自然語言中的符號(hào)又那么多,像漢語、韓語、日語等一個(gè)字節(jié)怎么能表示的過來,所以必須要有一個(gè)新的結(jié)構(gòu)字符來編碼。
A、ASCII碼
總共128個(gè),使用一個(gè)字節(jié)的低7位表示,0-31是控制字符如:換行、回車、刪除等;32-126是打印字符,可以通過鍵盤的輸入打印出來。
如:
System.err.println('A'+32);
char abcd = 'A' +32;
System.err.println(abcd);
得到:
B、ISO-8859-1
ISO提到這個(gè)名字我就想到了,食品安全上的那個(gè)。ISO組織在ASCII碼的基礎(chǔ)上利用單個(gè)字節(jié)的所有位定制了一系列標(biāo)準(zhǔn)擴(kuò)展ASCII編碼,ISO-8859-1仍然是單字節(jié)編碼,總共256個(gè)字符。我們下面提到的瀏覽器編碼規(guī)則就是依據(jù)于此。
C、GB2312
全稱《信息技術(shù)中文編碼字符串》,它采用雙字節(jié)編碼,范圍是A1-F7,其中A1-A9是符號(hào)區(qū)有682個(gè)符號(hào);B0-F7是漢字區(qū)包含6763個(gè)漢字。
D、GBK
全稱《漢字內(nèi)碼擴(kuò)展規(guī)范》是國(guó)家技術(shù)監(jiān)督局為windows95定制的新的內(nèi)碼規(guī)范,是擴(kuò)展GB2312用的,因?yàn)闈h字不止6763個(gè),你懂的。加入了更多的漢字,編碼范圍是8140-FEFE,總共23940個(gè)這下夠用了。
E、UTF-16
UTF-16定義了Unicode字符在計(jì)算機(jī)中的存取方法,UTF-16使用兩個(gè)字節(jié)表示Unicode的轉(zhuǎn)化格式,是固定長(zhǎng)度的表示方式,無論什么字符UTF-16都用兩個(gè)字節(jié)表示,兩個(gè)字節(jié)是16位,所以叫UTF-16你又懂得。
F、UTF-8
互聯(lián)網(wǎng)的普及,市面上所見之處都是UTF-8,是互聯(lián)網(wǎng)上使用最廣泛的Unicode實(shí)現(xiàn)方式(下面降Unicode)。上面所講UTF-16表示起來很方便了,但是存儲(chǔ)上是不是多占用了空間,因?yàn)闊o論你用不用都給你2個(gè)字節(jié)。而UTF-8編碼規(guī)則如下:
①對(duì)于單字節(jié)符號(hào),字節(jié)的第一位設(shè)為0,后7位是這個(gè)符號(hào)的Unicode碼。因此UTF-8包含ASCII碼。
②對(duì)于n位字節(jié)的符號(hào)(n>1),第一個(gè)字節(jié)都設(shè)為1,第n+1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。其余的都為這個(gè)符號(hào)的Unicode碼。
G、Unicode
就小編知道的編碼格式大概有30種左右吧,像阿拉伯文(ASMO 708)、俄語 - 西里爾文(DOS)、日文(Shift-JIS)、中國(guó) - 簡(jiǎn)體中文(GB2312)、繁體中文(Big5)、Unicode、Unicode (Big-Endian)、中歐(Windows)、西里爾文(KOI8-R)、 西里爾文(KOI8-U)、 阿拉伯文(ISO)、希伯來文(ISO-Visual)、希伯來文(ISO-Logical)、日文(JIS)、韓文(ISO)、日文(EUC)、韓文(EUC)、簡(jiǎn)體中文(HZ)、Unicode (UTF-7)、Unicode (UTF-8)等。
如果有一種編碼將世界上所有符號(hào)都納入其中,每一個(gè)符號(hào)都給予一個(gè)獨(dú)一無二的編碼,那么亂碼問題就不會(huì)有了對(duì)吧,這就是Unicode。Unicode是一個(gè)龐大的集合,可以容納百萬計(jì)符號(hào)。
在瀏覽器調(diào)試界面,我們選擇控制臺(tái),然后輸入document.charset即可獲取當(dāng)前界面的編碼規(guī)則。我們可以看到三種瀏覽器:谷歌、火狐、IE的編碼均為utf-8,因?yàn)槭腔ヂ?lián)網(wǎng)上使用最廣泛的Unicode實(shí)現(xiàn)方式:
客戶端想服務(wù)器發(fā)送請(qǐng)求四種情況:
1、表單post提交;
2、表單get提交;
3、頁(yè)面鏈接;
4、URL方式直接訪問
而URL包含中文無非有兩種情況:
1、url路徑包含中文即
https://abcd/測(cè)試/publish
這種類型的,從這么多年的上網(wǎng)經(jīng)驗(yàn)來講,我沒見過這種路徑。
2、url參數(shù)包含中文,這問題比較常見。
我們看到當(dāng)URl包含中文參數(shù)時(shí),瀏覽器做了轉(zhuǎn)碼。
這一點(diǎn)上,分兩種情況IE和非IE,因?yàn)镮E用的是GBK轉(zhuǎn)碼,非IE用的是Utf-8轉(zhuǎn)碼,而我們?cè)趙indows系統(tǒng)上查詢默認(rèn)的編碼就是GBK。
因此,你會(huì)發(fā)現(xiàn)IE瀏覽器好像對(duì)中文沒有做處理一般
在URL進(jìn)行參數(shù)傳遞的時(shí)候,要處理處理中文參數(shù)那么這里就要注意了,我們有三種解決方案(javascript轉(zhuǎn)碼、配置filter過濾器、修改中間件server.xml),這里我們考慮最簡(jiǎn)單的js轉(zhuǎn)碼方案。用戶從瀏覽器發(fā)起一個(gè)Http請(qǐng)求,存在編碼的地方是URL、Cookie、Parameter。服務(wù)器端接受到Http請(qǐng)求后要解析Http,其中URL、Cookie和Post表單參數(shù)需要解碼、服務(wù)器端還可能讀取數(shù)據(jù)庫(kù)數(shù)據(jù)或者文本文件,都可能存在編碼問題。當(dāng)servlet處理完所有請(qǐng)求數(shù)據(jù)后,再將這些數(shù)據(jù)編碼通過socket發(fā)送到用戶請(qǐng)求的瀏覽器里,經(jīng)瀏覽器解析成文本。
瀏覽器編碼URL是將非ASCII字符按照某種編碼格式,編碼成16進(jìn)制的數(shù)字后將16進(jìn)制數(shù)字表示的字節(jié)前加上%。這個(gè)過程就不太美了,因?yàn)椴煌瑸g覽器編碼方式可能還不一樣,那服務(wù)端怎么解,所以我們?cè)趹?yīng)用中盡量避免URl使用非ASCII字符。
問:要是避免不了怎么辦呢?
答:我們通過下面的例子一起探究
假如我們?cè)诘刂窓谥杏羞@樣的參數(shù)地址
http://localhost:2345/redant/test.action?name=測(cè)試
我們寫一個(gè)測(cè)試的小demo
<a onclick="test_decode(1)">測(cè)試轉(zhuǎn)碼問題1</a><br/>
<a onclick="test_decode(2)">測(cè)試轉(zhuǎn)碼問題2</a><br/>
<a onclick="test_decode(3)">測(cè)試轉(zhuǎn)碼問題3</a><br/>
<a onclick="test_decode(4)">測(cè)試轉(zhuǎn)碼問題4</a>
<script>
function test_decode(num){
var url = "";
switch (num) {
case 1:
url = "localhost:2345/redant/test.action?name=測(cè)試";
break;
case 2:
url = "localhost:2345/redant/test.action?name=測(cè)試";
url = encodeURI(url);
break;
case 3:
url = "localhost:2345/redant/test.action?name=測(cè)試";
url = encodeURI(encodeURI(url));
break;
default:
var name = “測(cè)試”;
name = encodeURIComponent(encodeURIComponent(name));
url = "localhost:2345/redant/test.action?name="+name;
break;
}
alert(url);
$.post(url);
}
</script>
A、在URL中直接傳遞漢字參數(shù),IE瀏覽器在java后臺(tái)得到的關(guān)于“測(cè)試”的編碼是:
但請(qǐng)求的URL并未將測(cè)試進(jìn)行轉(zhuǎn)碼。
火狐瀏覽器在java后臺(tái)得到的關(guān)于“測(cè)試”的編碼是:
谷歌瀏覽器在URL請(qǐng)求時(shí),已經(jīng)轉(zhuǎn)碼:%E6%B5%8B%E8%AF%95,
但在java后臺(tái)得到關(guān)于“測(cè)試”的編碼和火狐一樣:
也就是說火狐與谷歌在URL傳輸中文字符時(shí)會(huì)進(jìn)行了轉(zhuǎn)碼,但是轉(zhuǎn)碼后又被瀏覽器再次處理了。IE瀏覽器處理中文字符,不會(huì)自動(dòng)轉(zhuǎn)碼,但任然會(huì)被瀏覽器處理,也就是說那么我們拿url = "localhost:2345/redant/test.action?name=%E6%B5%8B%E8%AF%95";之后,三種瀏覽器的編碼解碼規(guī)則就一致了。
問:那么怎么實(shí)現(xiàn),三種瀏覽器編碼規(guī)則一致呢?
答:使用【encodeURI】進(jìn)行轉(zhuǎn)碼,利用encodeURI對(duì)中文URL參數(shù)進(jìn)行編碼時(shí),“測(cè)試”會(huì)轉(zhuǎn)為“%E6%B5%8B%E8%AF%95”,但瀏覽器機(jī)制會(huì)認(rèn)為”%”是一個(gè)轉(zhuǎn)義字符,瀏覽器會(huì)把地址URL中的傳遞的已轉(zhuǎn)換的參數(shù)”%”與”%”之間的轉(zhuǎn)義字符利用本身機(jī)制處理一遍后再傳遞給后臺(tái)所以我們使用encodeURI二次轉(zhuǎn)碼。
問:那么我們用encodeURI把中文字符二次轉(zhuǎn)碼保護(hù)起來,是不是就可以了呢?
答:經(jīng)過encodeURI轉(zhuǎn)碼之后,我們可以看到,在IE、谷歌、火狐“測(cè)試”的中文轉(zhuǎn)碼竟然一致了:
在 java后臺(tái)得到的關(guān)于“測(cè)試”的編碼,三種瀏覽器竟然也一致了:
小編看到網(wǎng)絡(luò)上有好多例子說:在java后臺(tái)通過
java.net.URLDecoder.decode(name, "Utf-8");
就可以解析“測(cè)試”了。
然而小編得到的卻是:
小編懵逼的再問:這到底是什么編碼?
java.net.URLDecoder.decode(name, "Utf-8");
java.net.URLDecoder.decode(name, "GBK");
java.net.URLDecoder.decode(name, "ISO-8859-1");
java.net.URLDecoder.decode(name, "GB2312");
java.net.URLDecoder.decode(name, "UTF-16");
java到底該怎么解析這個(gè)編碼,等等為啥會(huì)帶有”/”,那去掉之后呢?
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"));
終于如愿以償了
【encodeURI()與encodeURIComponent()】效果一樣。也是不得已而為之的一種方法。
【TODO】
果然如此,小編留下一個(gè)待測(cè)試的地方:就是不同的瀏覽器,不同的系統(tǒng),是否都可以使用這個(gè)方法。
問:那么為什么會(huì)出現(xiàn)”/”呢?小編不得而知。
上面我們看到,編碼如果解析失敗,會(huì)出現(xiàn)
①一個(gè)漢字變成兩個(gè)亂碼字符
這種情況是因?yàn)?,字符串在解碼時(shí),所使用的字符集與編碼的字符集不一致導(dǎo)致的,例如用GBK編碼用ISO-8859-1解碼,一個(gè)漢字變成了兩個(gè)亂碼字符。
②一個(gè)漢字變成兩個(gè)問號(hào)
這情況就復(fù)雜了,可能是中文經(jīng)過多次編碼造成的,出現(xiàn)這情況你就要仔細(xì)看中間編碼環(huán)節(jié),然后找出編碼錯(cuò)誤的地方。例如:一個(gè)漢字拿GBK編碼,然后用ISO-8859-1解碼,發(fā)現(xiàn)不對(duì),然后再拿GBK編碼,最后再拿GBK解碼的過程。
③一個(gè)漢字變成一個(gè)問號(hào)
將中文和中文符號(hào)經(jīng)過不支持中文的ISO-8859-1編碼后,所有字符變成”?”,這是因?yàn)镮SO-8859-1進(jìn)行編碼是遇到不在碼值范圍內(nèi)的字符統(tǒng)一用3f表示,因此都變成了”?”。例如:一個(gè)漢字拿ISO-8859-1編碼,再拿ISO-8859-1解碼的過程。
④我們跨網(wǎng)站推送數(shù)據(jù)的時(shí)候,有時(shí)候用
String name = request.getParameter(“name”);
然后
Name = new String(name.getBytes(“ISO-8859-1”, “GBK”));
竟然得到了正確的中文字符,這是怎么回事?
其實(shí)通常是這樣的,我們將漢字用GBK編碼之后,然后用ISO-8859-1解碼得到的當(dāng)然是我們第一種所提到的那樣,然后既然不行那我再拿ISO-8859-1編碼回去,用GBK解碼。這就是那個(gè)過程。
有人會(huì)問了,為啥不直接用GBK解碼,而是中間走一下ISO-8859-1呢?
答:因?yàn)镮SO-8859-1是大多數(shù)瀏覽器的默認(rèn)字符集,還有一些中間件的默認(rèn)編碼也是。小編聯(lián)想到,encodeURI()它采用的是UTF-8格式輸出編碼后的字符串。也就是說,我們可以在瀏覽器中只進(jìn)行一次轉(zhuǎn)碼就好。
url = "localhost:2345/redant/test.action?name=測(cè)試";
url =encodeURI(url);
我們?cè)诤笈_(tái)按照utf-8來轉(zhuǎn)就好了,即
name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
當(dāng)然如果編碼中有多余的“/”,要處理掉。
答:兩種
①I/O流中,需要指定charset。
②內(nèi)存操作,也就是項(xiàng)目運(yùn)行的過程中。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。