標籤:style blog http java 使用 os strong 檔案
使用者從瀏覽器發起一個HTTP請求,存在編碼的地方是URL、Cookie、Paramiter。伺服器端接收到HTTP請求後要解析HTTP協議,其中URL、Cookie和POST表單參數要解碼,伺服器端可能還需要讀取硬碟資料(資料庫、檔案),這些資料都可能存在編碼問題。當Servlet處理完所有請求的資料後,需要將這些資料再編碼通過Socket發送到使用者請求的瀏覽器裡,再經過瀏覽器解碼成為文本。這些過程用圖表示如下:
1.URL的編解碼
為了驗證瀏覽器是怎麼編碼URL的,我們選擇FireFox瀏覽器並通過HTTPFox外掛程式觀察請求的URL的實際內容:
從結果上看,PathInfo是UTF-8編碼,而QueryString是GBK編碼。至於為什麼有%,是由URL的編碼規範FRC3986規定:瀏覽器編碼URL將非ASCII字元按照某種編碼格式編碼成16進位數字後將每個16進位表示的位元組前加上“%”。
從上面的測試結果可知,瀏覽器對PathInfo和QueryString的編碼是不一樣的,不同的瀏覽器對PathInfo的編碼也可能不一樣。如Chrome會對請求“http://localhost:8080/中國?中國”轉變為“http://localhost:8080/%E4%B8%AD%E5%9B%BD?%E4%B8%AD%E5%9B%BD”,這裡PathInfo和QueryString的編碼是一樣的,都是UTF-8編碼。
2.HTTP Header的編解碼
當用戶端發起一個HTTP請求時,除了上面的URL外還可能會在Header中傳遞其他的參數,如Cookie、redirectPath等,這些使用者佈建的值很可能也會存在編碼問題。
在Tomcat中,對Header中的項進行解碼是在調用request.getHeader時進行的,如果請求的Header項沒有解碼則調用MessageBytes的toString方法,這個方法將從byte從char的轉化使用的預設編碼是ISO-8859-1,而我們也不能設定Header的其他解碼格式,所以如果你設定的Header中非ASCII字元解碼肯定會有亂碼。
我們在添加Header時也是同樣的道理,不要在Header中傳遞非ASCII字元,如果一定要傳遞可以先將字元用org.apache.catalina.util.URLEncoder編碼,然後再添加到Header中,這樣在瀏覽器到伺服器的傳遞中就不會丟失資訊了,我們在訪問這些項時再按照相應的字元集解碼就好了。
3.POST表單的編解碼
POST表單參數傳遞方式與QueryString不同,它是通過HTTP的BODY傳遞到服務端的。當我們在頁面上點擊提交按鈕時瀏覽器首先將根據頁面的ContentType的Charset編碼格式對錶單填的參數進行編碼,然後提交到伺服器端。在伺服器端同樣也是用ContentType中的字元集進行解碼。所以通過POST表單提交的參數一般不會出現問題,而且這個字元集編碼是我們自己設定的。
另外,針對multipart/form-data類型的參數,也就是上傳的檔案編碼,同樣也使用ContentType定義的字元集編碼。值得注意的地方是,上傳檔案是用位元組流的方式傳輸到伺服器的本地臨時目錄,這個過程並沒有涉及字元編碼,而真正編碼是在將檔案內容添加到parameters中時,如果用這個不能編碼將會用預設編碼ISO-8859-1來編碼。
4.HTTP BODY的編解碼
當使用者請求的資源服務端已經成功擷取後,這些內容將通過Response返回給用戶端瀏覽器,這個過程先要經過編碼再到瀏覽器進行解碼,瀏覽器根據HTML的<meta HTTP-equiv=“Content-Type” content=”text/html; charset=GBK”>中的charset來解碼。如果沒有定義,那麼瀏覽器將會使用預設的編碼來解碼。
訪問資料庫都是通過用戶端JDBC驅動來完成的,用JDBC來存取資料要和資料的內建編碼保持一致,可以通過設定JDBC URL來指定。
5.JS中的編解碼
html檔案本身中的js的編碼和當前頁面中的Content-Type保持一致。
對於採用<script src=”script.js”/>類型引入的js檔案,瀏覽器就會以當前這個頁面的預設字元集解析這個JS檔案,如果外部的JS檔案的編碼格式與當前頁面的編碼格式一致,那麼可以不設定這個charset。但是如果script.js檔案的編碼格式與當前頁面的不一致,就必須要指定對應的字元集,要不然對於非ASCII字元就會出現亂碼。
6.其他需要編碼的地方
除了URL和參數編碼問題外,在服務端還有很多地方可能存在編碼,如可能需要讀取XML、Velocity模板引擎、JSP或者從資料庫讀取資料等。
參考資料:《深入分析Java Web技術》