Java作為跨平台語言,涉及到的編解碼問題也比較多,我們來探讨一下HTTP請求如何控制編碼格式。
幾種常見的編碼格式
為什麼要編碼
由于計算機隻能看懂01,人類隻能看懂字元,是以要進行編碼和解碼。
1 在計算機中,一個位元組是最小的資訊存儲單元,而一個位元組隻能表示256個字元。
2 人類需要的符号遠遠超過256個。
如何翻譯
各種語言需要交流,如何進行翻譯呢,在計算機中提供了常見的翻譯方式。比如ASCII,UTF-8等編碼方式,他們可以被看做字典,可以讓位元組數組變成對應的字元。那麼他們有什麼差別呢。
1 ASCII碼
一共有128個,用一個位元組的低七位表示。
2 ISO
128個字元顯然不夠用,于是在ASCII基礎上建立了ISO-8559編碼。雖然仍是單位元組,但可以表示256字元。
3 GB2312
是雙位元組編碼,可以表示6763個漢字
4 GBK
它擴充了GB2312,功能表示21003個漢字。他和GB2312互相相容
5 UTF-16
首先說下Unicode,ISO試圖履歷一個超語言詞典,讓所有語言都可以通過這個字典翻譯。這是非常複雜的。
UTF-16定義了Unicode字元在計算機中的存儲方法,UTF-16用兩個位元組來表示Unicode的轉化格式,并且使用定長的方法,無論什麼字元都可以用2個位元組表示。
這大大簡化了字元串操作,是以Java使用UTF-16作為記憶體字元的存儲格式。
6 UTF-8
UTF-16統一使用兩個位元組表示一個字元,雖然很簡單,但是很多字元隻需要一個位元組就可以表示了,相當于多處用了一倍的空間。
在網絡帶寬有限的情況下,沒有必要。UTF-8使用變長技術,每個編碼區有不同的字碼長度。所有字元可以用1-6個位元組組成。
如果是一個位元組的字元那麼就是ASCII碼了
Java中需要編碼的場景
io操作中存在的編碼
位元組流到字元流的互相轉換需要用到編碼
記憶體操作中的編碼
使用String字元串和byte數組進行互相轉換時,需要指定編碼
Java中如何編解碼
一般指定charsetname為指定編碼格式即可。
各種編碼實踐
略
對幾種編碼格式的比較
1 對于中文字元,使用GBK好一點
2 對于Unicode字元,使用UTF-16的編碼效率較高,轉換更簡單,進行字元串操作也更好,适合在磁盤和記憶體之間使用,但是不适合進行網絡傳輸,因為雙位元組容易損壞,且占用空間大。
3 UTF-8更适合網絡傳輸,UTF-8使用單位元組存儲,單個字元損壞不影響其他字元。
Java Web中設計的編解碼
對于http網絡傳輸,考慮壓縮資料,減少網絡傳輸量,但是有的壓縮算法隻減少字元數但是不減少位元組數。
在計算機中,漢字的表示方式一般是一個字元使用兩個位元組來表示,是以Java的char類型也是16個bit,也就是2個位元組。
JavaWeb可能出現編碼轉換的地方:
1 HTTP請求中的URI,Cookie,Post表單參數需要解碼。
2 資料庫的讀寫,檔案讀寫需要編解碼。
3 所有資料從socket傳回時需要編碼,浏覽器解析頁面需要解碼。
URL的編解碼
一個URL可以被分為好多個組成部分
http://localhost:8080/hello/servlet/黃蓬龍?name=h2pl
scheme domain port context servletpath pathinfo querystring
這部分中,url不包括querystring,uri則隻包括hello/servlet/黃蓬龍,也就是context+servletpath+pathinfo。
是以uri隻是定位資源,但是不包括網絡協定
對于Tomcat而言,servlet會把這個url解析為一下幾個部分。
事實上一部配置設定置是在server.xml配置檔案中定義的。
1 port是配置檔案中的connector port定義的。
2 context path是在配置檔案中定義的
3 servletpath是web.xml的url-pattern中定義的。
4 pathinfo是我們具體請求的servlet
5 querystring是要傳遞的參數
pathinfo采用utf-8編碼,querystring采用gbk編碼
總結就是,url的編解碼過程比較複雜,不是我們在應用中能控制的,是以盡量避免在url中使用非ASCII字元。
HTTP header的編解碼
同理,預設使用ISO編碼且不能改變,是以不用有非ASCII字元。
POST表單的編解碼
post使用body傳遞資料,而header中設定了contenttype,是以我們根據這個編碼格式進行編解碼即可。
http body的編解碼
上面講過了。
另外JDBC的編碼設定要和資料庫内置的資料編碼保持一緻。
在JS中的編碼問題
外部引入JS檔案
引入時需要設定編碼,否則可能亂碼
JS的URL編碼
略
其他需要編碼的地方
1 xml可以設定頭指定編碼格式
2 velocity模闆設定編碼
3 jsp設定編碼
常見問題分析
中文字元變亂碼
編碼解碼的字元集不一緻
一個漢字變成問号
将中文經過ISO編碼(不支援中文)後會變成?
一個漢字變成兩個問号
可能是多次編碼過程中出錯。
不正常的正确編碼
略
微信公衆号
個人公衆号:程式員黃小斜
微信公衆号【程式員黃小斜】新生代青年聚集地,程式員成長充電站。作者黃小斜,職業是阿裡程式員,身份是斜杠青年,希望和更多的程式員交朋友,一起進步和成長!專注于分享技術、面試、職場等成長幹貨,這一次,我們一起出發。
關注公衆号後回複“2020”領取我這兩年整理的學習資料,涵蓋自學程式設計、求職面試、算法刷題、Java技術學習、計算機基礎和考研等8000G資料合集。

技術公衆号:Java技術江湖
微信公衆号【Java技術江湖】一位阿裡 Java 工程師的技術小站,專注于 Java 相關技術:SSM、SpringBoot、MySQL、分布式、中間件、叢集、Linux、網絡、多線程,偶爾講點Docker、ELK,同時也分享技術幹貨和學習經驗,緻力于Java全棧開發!
關注公衆号後回複“PDF”即可領取200+頁的《Java工程師面試指南》強烈推薦,幾乎涵蓋所有Java工程師必知必會的知識點。