深入分析java Web技術內(nèi)幕 - 編碼(3)

為什么要編碼?

計算機存儲信息的最小單位是1byte,即8bit,所能表示的字符個數(shù)為255個,但是人類要表示的符號太多,遠遠不止255個,西歐字符、中文等等符號。

解決這個問題,就必須要有一個新的數(shù)據(jù)結構,在java中就是char,從char到byte必須編碼(可以理解為翻譯)

常見編碼格式(字典)
  1. ASCⅡ
    由于計算機最早是由美國發(fā)明的,根據(jù)他們的語言習慣,用1個字節(jié)可以表示128個字符,可以通過鍵盤輸入并且能夠顯示出來
  2. ISO-8859-1
    應用最廣泛的編碼格式,占用2個字節(jié)可以表示256個字符,涵蓋大部分的西歐語言字符。
  3. 中文編碼
    • GB2312
      包含682個字符和6763個漢字
    • GBK
      總共有23940個碼位,能表示21003個漢字,兼容GB2312
    • GB18030
      國家標準,兼容GB2312,但是應用不廣泛
  4. Unicode
    統(tǒng)一編碼,是計算機科學領域里的一項業(yè)界標準,包括字符集、編碼方案。
  5. UTF-16
    用兩個字節(jié),將Unicode字符轉(zhuǎn)換為字節(jié)存儲。Java以UTF-16作為內(nèi)存的字符存儲格式
  6. UTF-8
    變長,1-6個字節(jié)
Java中的編碼場景

磁盤I/O 和 網(wǎng)絡I/O

磁盤I/O
  • 字符轉(zhuǎn)字節(jié):OutputStreamWriter作為橋梁,傳入字符集charset,委托StreamDecoder去做具體的字符轉(zhuǎn)字節(jié)的工作
  • 字節(jié)轉(zhuǎn)字符:InputStreamReader 作為橋梁,傳入字符集charset,委托StreamDecoder去做具體的字節(jié)轉(zhuǎn)字符的工作
 //字符轉(zhuǎn)字節(jié)
    @Test
    public void charToByteByDiskIo() {
        String path = CodeProgram.class.getResource("").getPath();
        File file = new File(path, "字符轉(zhuǎn)字節(jié)流,通過字符寫入磁盤文件.txt");
        FileOutputStream fos = null;
        OutputStreamWriter osw = null;
        try {
            fos = new FileOutputStream(file);
            osw = new OutputStreamWriter(fos, "utf-8");
            osw.write("我愛中國,我愛香港!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(null != osw) {
                    osw.close();
                }
                if(null != fos) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
//字節(jié)轉(zhuǎn)字符:打印當前java類的內(nèi)容到控制臺(如果eclipse中的workspace文件編碼未改為utf-8或者測試方法所屬的java類的文件編碼沒有改為utf-8,則會亂碼)
@Test
    public void byteToCharByDiskIo() {
        File directory = new File("./src");
        File file = new File(directory, "CodeProgram.java");
        FileInputStream fis = null;
        InputStreamReader isr = null;
        try {
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis, "utf-8");
            StringBuffer sb = new StringBuffer();
            char[] cbuf = new char[1024];
            int length = 0;
            while((length = isr.read(cbuf)) != -1) {
                sb.append(cbuf, 0, length);
            }
            System.out.println(sb.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(null != isr) {
                    isr.close();
                }
                if(null != fis) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
網(wǎng)絡I/O
  1. URL的編解碼
  2. HTTP Header的編解碼
  3. POST表單的編解碼
  4. HTTP Body的編解碼
  5. 外部引入JS文件
  6. JS的URL編碼及服務端解碼
  7. 其他需要編碼的地方
    以Tomcat服務器為例講解
  1. URL的編解碼
    Get請求,URL的pathinfo(路徑)和Query String(參數(shù))的編碼字符集不同,瀏覽器將URL中非ASCⅡ碼字符按某種字符集轉(zhuǎn)換為16進制到字符加上%。
    tomcat設置URI解碼字符集為UTF-8:<Connector URIEncoding="UTF-8" />
    tomcat設置Query String解碼字符集為UTF-8:<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true" />
  2. HTTP Header的編解碼

    默認為ISO-8859-1,且不提供編碼設置到方法,只能用URLEncoder編碼,服務端request.getHeader時,再相應到用URLEncoder解碼

  3. POST表單的編解碼

    手動指定編碼格式, request.setCharacterEncoding(charset),post表單提交到數(shù)據(jù)就是以指定到編碼格式編碼,再調(diào)用request.getParameter(),會自動用設定到編碼去解碼。
    一定要在調(diào)用request.getParameter()方法前調(diào)用request.setCharacterEncoding(charset),否則tomcat在解析前會檢測HTTP Header中到contentType,一般請求時,這個值是null,根據(jù)tomcat源碼,為空時,按默認到到字符集ISO-8859-1來編碼,導致亂碼

  4. HTTP Body的編解碼

    請求資源成功獲取后,這些內(nèi)容將通過response返回給客戶端瀏覽器。通過response.setCharacterEncoding(charset)設置編解碼字符集,通過response Header的contentType返回給客戶端,瀏覽器根據(jù)contentType解碼,如果不存在,則根據(jù)html <meta/>中到charset來解碼,如果都不存在,則用默認到ISO-8859-1解碼

  5. 外部引入JS文件

    如果在一個單獨到js腳本中包含中文輸出,需指定字符集<script src="" charset="gbk" />
    如果被一個頁面引入到js腳本,則與外部頁面到編碼方式一致,若js文件本身到編碼格式與外部頁面編碼格式不一致,則會亂碼

  6. JS的URL編碼及服務端解碼
    • encodeURI()
    • encodeURIComponent()

    除了特殊字符加英文字母不編碼加%外,其余到都編碼;后者到特殊字符范圍縮小,特別是&符號不包含在內(nèi),&符號也要編碼。所以后者常用來對一個URL傳遞一個參數(shù)值為URL的URL進行編碼。后臺對應到解碼JAVA類為URLDecoder。前端JS兩次編碼,后端request.getParameter()自動解一次碼,URLDecoder.decoder手動解一次碼。兩次編解碼避免了前后端第一次編解碼不一致的問題。

  7. 其他需要編碼的地方
    • 數(shù)據(jù)庫連接JDBC URL傳遞characterEncoding=gbk,與數(shù)據(jù)庫內(nèi)置編碼格式要一直
    • XML
    • JSP
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容