編碼(三):Java Web編碼問題
問題描述:
今天在測試產品的時候發現使用HttpUrlClient傳送POST表單資料,當資料量>=1M的時,後臺報錯,原因分析如下:
一、HTTP協議對資料大小的限制
根據RFC規定,HTTP1.1本身並沒有對GET和POST方法進行引數大小限制,但是不同的瀏覽器和WEB伺服器對資料大小會做限制,比如:
不同瀏覽器對URL長度的限制(字元)
IE : 2803 Firefox:65536 Chrome:8182 Safari:80000 Opera:190000
WEB伺服器對POST資料長度限制:
Tomcat預設大小為2M,可以修改配置:maxPostSize="0",取消對資料大小的限制。
二、Tomcat預設大小為2M,為什麼超過1M資料就會報錯
經過檢視,發現在使用HttpUrlClient與後臺互動時,POST資料處理如下:
1.使用 String data = "content=" + URLEncode.encode("XXXXX......", "utf-8"),對資料進行編碼;
2.在傳遞資料時outputStream.writer(data.getByte("utf-8"));
這個過程進行了兩次UTF-8編碼使位元組數變大。問題解決了,但藉此機會瞭解下WEB中的編碼方式。以下內容學習總結與《深入分析Java WEB技術內幕》。
三、WEB中的編解碼
URL編解碼:(URL中存在中文的情況)
http:協議 localhost:域名 8080:埠 /examples/servlets/servlet/屌絲男士:URI examples:ContextPath servlets/servlet/:ServeltPath 屌絲男士:PageInfo name=屌絲男士:QueryString
通過谷歌瀏覽器觀察:
其中PageInfo採用了UTF-8編碼,而QueryString也採用了UTF-8編碼。至於為什麼會“%”,根據RFC3986可知瀏覽器編碼URL將非ASCII字元按照某種編碼格式程式設計16進位制數字後將每個16進製表示的位元組前加上“%”。
a.不同的瀏覽器對 pageInfo 的編碼方式不同,Tomcat對URL中URI的解碼字符集是在connector中定義的,預設為ISO-8859-1。<Connector URIEncoding="UTF-8"/>
b. QueryString的解碼字符集是在是在 Header 中 Content-Type 中,通過 charset 定義的,預設為 IOS-8859-1, 但是要使用 Content-Type 中定義的編碼,就要在 connector 中進行如下的設定:
<Connector useBodyEncodingForURI="true"/>
URL 的編碼和解碼過程比較複雜,並不都由我們自己能完全控制,所以儘量在 URL 中使用非 ASCII 字元。
POST 表單的編解碼
POST 表單型別的引數傳遞方式與 QueryStirng 方式不同,是通過 HTTP Body 方式傳遞到伺服器端的,它根據 Content-Type 中的 charset 規定的格式進行編碼,在伺服器端也通過 Content-Type 中對字元編碼方式進行解碼。
HTTP Body 中的編解碼
響應的內容通過 Header 中的 Content-Type 返回客戶端,瀏覽器通過 Content-Type 的 charset 進行解碼。如果返回的 Content-Type 中沒有設定 charset 值,那麼瀏覽器將根據 HTML 的
<meta HTTP-equiv="Content-Type" content="text/html; charset=utf-8" />
來進行解碼。