第三章 深入分析Java Web中的中文编码问题
3.1 幾種常見的編碼格式
3.1.1 為什么要編碼
一個字節 byte只能表示0~255個符號,要表示更多的字符,需要編碼。
3.1.2 如何翻譯
ASCII碼:有128個,用一個字節的低7位表示。
ISO-8859-1,能表示256個,是單字節編碼。
GB2312: 雙字節編碼,
GBK:是對GB2312的擴展,加入更多漢字,和GB2312兼容,BG2312編碼的漢字可以用GBK來解碼,不會亂碼。
GB18030:
? ? ? ? ??
? ? ? ? UTF-16:Unicode(統一碼),ISO創建的全新的超語言字典。Unicode是JAVA和XML基礎。 注意: Unicode是編碼,也就是碼和漢字(或其他國家語言)的對應關系。但是具體如何把這些編碼存儲,則要采取不同的編碼方式,比如UTF-16和UTF-8。UTF-16就用固定兩個字節表示一個UNicode編碼。因為是固定兩個字節的長度,所以操作起來很簡單,這也是JAVA以UTF-16作為字符的內存存儲格式的原因。
? ? ? ? UTF-8: UTF的缺點是浪費,因為很多字符用一個字節就夠了,用不上兩個字節。
? ? ? ? UTF-8的編碼規則: ?如果一個字節最高位為0,XXX
如果一個字節以11開頭,XXX
? ? ?如果一個字節以10開頭,XXX? ?
3.2 在JAVA中需要編碼的場景
? ? ?什么場合需要編碼
3.2.1 在I/O操作中存在的編碼
在字符到字節或從字節到字符的轉換,而這種轉換的場景主要是I/O. ?I/O包括磁盤和網絡兩種I/O.
Reader類是在JAVA IO讀字符的父類,而inputstream類是讀字節的父類,InputStreamReader類就是關聯字節到字符的橋梁,字節到字符的轉換,而對具體字節到字符的編碼實現,它又委托StreamDecoder去做,解碼過程中必須制定Charset,如果沒有制定,則將使用本地環境中的默認字符集,如在中文環境中使用GBK。? ? ?
package ioTest;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException;public class decodeTest {public static void main(String[] args) {String file = "XXX.txt";String charset = "UTF-8";try {FileOutputStream outputStream = new FileOutputStream(file);try {OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset);try {writer.write("要保存的中文字符");} catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace();}} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch block e.printStackTrace();}} catch (FileNotFoundException e) {// TODO Auto-generated catch block e.printStackTrace();}finally{writer.close();}} }3.2.2 在內存操作中編碼
字節和字符轉換:
String s = "lfdasjlfjasljfasfa"; byte[] b = s.getBytes("UTF-8"); String n = new String(b, "UTF-8");byte[] 和 char[]之間編碼和解碼:
String string = "fsdfsd"; Charset chars = Charset.forName("UTF-9"); ByteBuffer byteBuffer = chars.encode(string); CharBuffer charBuffer = chars.decode(byteBuffer);3.3 在JAVA中如何編碼
3.3.1 按照ISO-8859-1編碼
3.3.2 按照GB2312編碼
3.3.3 按照GBK編碼
3.3.4 按照UTF-16編碼
3.3.5 按照UTF-8編碼
3.3.6 編碼UTF-8編碼代碼片段
3.3.7 幾種編碼格式的比較
GBK是對GB2312擴展,可以表示所有的漢字。
? ? ? ?UTF-8比UTF-16更適合網絡傳輸
3.4 在JAVA web中編解碼
?
http請求過程中,存在編碼的地方是:
?
? ? ? ? ? ? ? 前段發過啦來的URL, cookie, ?Parameters。
?
服務器接收到HTTP請求后,要解析HTTP,其中URL,cookie和POST表單參數需要解碼。
?
服務器可能讀網絡和本地的文件和DB,可能存在編碼問題。
?
當servlet處理完所有請求后,需要將這些數據再編碼,發送給瀏覽器。
?
?3.4.1 URL的編解碼
URL可能存在中文,所以需要編碼。
瀏覽器編碼URL是將非ASCII字符按照某種編碼格式編碼成16進制數字后將每個16進制表示的字符前加上%。
瀏覽器可以設置編碼格式。
Tomcat是如何解碼的?
? ? ? ? ? ? ? ? ?’URL的URI部分進行解碼的字符集是在<Connector URIEncodeing="UTF-8">里設置的。
? ?QueryString的解析過程:GET方式HTTP請求的querystring和POST方式HTTP請求的表單參數都是作為parameters保存的,都通過request.getParameter();
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?queryString的解碼字符集是在哪定義的呢? 是在HTTP的header的contentType或者是默認的ISO-8859-1,如果要用HTTP的header中
中定義的編碼需要設置<Connector URIEncoding="UTF-8" ? ? ?useBodyEncodingForURI='true'>
?
3.4.2 HTTP Header的編解碼
除了上面的URL外,還可能在header中傳遞其他參數,如cookie,redirectPath等。這些用戶設置的值也可能存在編碼問題。
? ? ? ?對Header的解碼是在調用request.getHeader()時進行的。默認是按照ISO-8859-1,如果header中有非ASCII,會亂碼。
? ? ? ?如果要用header傳遞中文,可以傳之前編碼,然后解碼:
1、客戶端
method.addRequestHeader("hello",URLEncoder.encode("中文","UTF-8"));
2、服務器
value=URLDecoder.decode(value);
3.4.3 POST表單的編解碼
POST表單提交的參數的解碼是在第一次調用request.getParameter時發生的,與queryString不同,是通過HTTP的body傳遞的,當提交表單的時候,根據ContentType的charset編碼格式對表單中填入的參數編碼,然后提交到服務器,在服務器端也用contentType來解碼。這個編碼、解碼的字符集使我們自己設置的。
? ? ? ? ? ? ? 注意一定要在第一次調request.getParameter方法之前就設置request.setCharacterEncoding(charset), 否則會亂碼。
3.4.4 HTTP BODY的編解碼
? ? ? ? ? ? ?response.setCharacterEcoding可以設置編碼方式,覆蓋request.getCharacterEncoding的值,并且通過contentType返回給客戶端。瀏覽器根據content-Type解碼;如果么有這個值,按照HTML中的charset來解碼。
? ? ? ? ? ? ?和JDBC的編碼方式要一致。
3.5 在JS中的編碼問題
3.5.1 外部引入JS文件
? ? ? ? ? 如何js文件本身的編碼和JS中使用的字符編碼不一致,可能就有亂碼。比如*.js文件是UTF-8,而頁面是GBK,就會有亂碼問題。
3.5.2 JS的URL編碼
Ajax的http_request('get', url, ture)調用,URL在IE下用OS的默認編碼,在Firefox下是UTF-8編碼。
JS有三個函數是和編碼解碼相關的。
? ? ? ? JAVA是如何來解碼的?JAVA端處理URL編碼、解碼有連個類: ? 分別是Java.net.URLEncoder和java.net.URLDecoder
3.5.3 其他需要編碼的地方
3.6 常見問題分析
3.6.1 中文變成了看不懂的字符
解碼和編碼用的字符集不一樣,就會出現亂碼。
3.6.2 一個漢字變成一個問號
ISO-8859-1遇到不認識的用3F表示,是問號。
3.6.3 一個漢字變成兩個問號
3.6.4 一種不正常的正確編碼
3.7 一種繁簡轉換的實現方式
3.8 總結
轉載于:https://www.cnblogs.com/liufei1983/p/7384317.html
總結
以上是生活随笔為你收集整理的第三章 深入分析Java Web中的中文编码问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springmvc + mybatis
- 下一篇: Codeforces 543 B. Wo