請求編碼、響應編碼及URL編碼的原理

1 請求編碼


1.1 直接在地址欄中給出中文

請求數據是由客戶端瀏覽器發送服務器的,請求數據的編碼是由瀏覽器決定的。例如在瀏覽器地址欄中給出:http://localhost:8080/hello/AServlet?name=傳智,那麼其中“傳智”是什麼編碼的呢?不同瀏覽器使用不同的編碼,所以這是不確定的!

IE:使用GB2312;

  FireFox:使用GB2312;

  Chrome:使用UTF-8;

 

  通常沒有哪個應用要求用戶在瀏覽器地址欄中輸入請求數據的,所以大家只需瞭解一下即可。


1.2 在頁面中發出請求

通常向服務器發送請求數據都需要先請求一個頁面,然後用戶在頁面中輸入數據。頁面中有超鏈接和表單,通過超鏈接和表單就可以向服務器發送數據了。

因爲頁面是服務器發送到客戶端瀏覽器的。的,所以這個頁面本身的編碼由服務器決定。而用戶在頁面中輸入的數據也是由頁面本身的編碼決定。

例如:

<!DOCTYPE html>
<html>
  <head>
    <title>index.html</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> //這就相當於給客戶端發送了響應頭content-type,
									  //指定當前頁面的編碼爲utf-8

  </head>
  
  <body>
<form action="/hello/servlet/AServlet">
  名稱:<input type="text" name="name"/>
  <input type="submit" value="提交"/>
</form>
<a href="/hello/servlet/AServlet?name=張三">鏈接</a>
  </body>
</html>

當用戶在index.html頁面中輸入數據時,都是UTF-8編碼的。因爲這個頁面本身就是UTF-8編碼的!

1.3 POST請求解讀編碼

  當客戶端通過POST請求發送數據給服務器時,因爲POST請求參數在請求體中,所以是可以設置編碼的。可以在使用request.getParameter()獲取請求參數之前先通過request.setCharacterEncoding()來指定服務器解碼請求參數時使用的編碼字符集,然後再使用reuqest.getParameter()方法來獲取請求參數,那麼就是用指定的編碼來讀取了。

也就是說,如果是POST請求,服務器可以指定編碼!但如果沒有指定編碼,那麼默認還是使用ISO-8859-1來解讀。

request.setCharacterEncoding(“utf-8”);

String name =request.getParameter(“name”);

1.4 GET請求解讀編碼

當客戶端通過GET請求發送數據給服務器時,沒有方法可以設置它的編碼,因爲參數在url中。使用request.getParameter()獲取的數據是被服務器誤認爲ISO-8859-1編碼的,也就是說客戶端發送過來的數據無論是UTF-8還是GBK,服務器都認爲是ISO-8859-1,這就說明我們需要在使用request.getParameter()獲取數據後,再轉發成正確的編碼。

例如客戶端以UTF-8發送的數據,使用如下轉碼方式:

String name =request.getParameter(“name”);
name = newString(name.getBytes(“iso-8859-1”), “utf-8”);


注意:request請求【默認】是不能通過  request.setCharacterEncoding();   指定服務器對請求參數解碼時使用的編碼字符集,

 但是,可以通過在tomcat的server.xml中,設置<Connector ….>元素的屬性URIEncoding="UTF-8”。(默認沒有設置此屬性),指定URI使用“UTF-8”編碼方式。

然後,request請求也可以和post請求一樣,使用equest.setCharacterEncoding();來指定服務器解碼請求參數時使用的編碼字符集


2 響應編碼


響應:服務器發送給客戶端數據!響應是由response對象來完成,如果響應的數據不是字符數據,那麼就無需去考慮編碼問題。當然,如果響應的數據是字符數據,那麼就一定要考慮編碼的問題了。

response.getWriter().print(“傳智”);

上面代碼因爲沒有設置repsonse.getWriter()字符流的編碼,所以服務器使用默認的編碼(ISO-8859-1)來處理,因爲ISO-8859-1不支持中文,所以一定會出現編碼的。

所以在使用response.getWriter()發送數據之前,一定要設置response.getWriter()的編碼,這需要使用response.setCharacterEncoding()方法設置服務器的編碼方式,

response.setCharacterEncoding(“utf-8”);

response.getWriter().print(“傳智”);

上面代碼因爲在使用response.getWriter()輸出之前已經設置了編碼,所以輸出的數據爲utf-8編碼。但是,因爲沒有告訴瀏覽器使用什麼編碼來讀取響應數據,所以很可能瀏覽器會出現錯誤的解讀,那麼還是會出現亂碼的。

當然,通常瀏覽器都支持來設置當前頁面的編碼,如果用戶在看到編碼時,去設置瀏覽器的編碼,如果設置的正確那麼亂碼就會消失。但是我們不能讓用戶總去自己設置編碼,而且應該直接通知瀏覽器,服務器發送過來的數據是什麼編碼,這樣瀏覽器就直接使用服務器告訴他的編碼來解讀!這需要使用content-type響應頭

response.setContentType(“text/html;charset=utf-8”);

response.getWriter().print(“傳智”);

  上面代碼使用setContentType()方法設置了響應頭content-type編碼爲utf-8,這不只是在響應中添加了響應頭,還等於調用了一次response.setCharacterEncoding(“utf-8”),也就是說,通過我們只需要調用一次response.setContentType(“text/html;charset=utf-8”)即可,而無需再去調用response.setCharacterEncoding(“utf-8”)了。

 

在靜態頁面中,使用<meta>來設置content-type響應頭,例如:

<metahttp-equiv="content-type" content="text/html;charset=UTF-8">


3 URL編碼



通過頁面傳輸數據給服務器時,如果包含了一些特殊字符是無法發送的。這時就需要先把要發送的數據轉換成URL編碼格式,再發送給服務器。

其實需要我們自己動手給數據轉換成URL編碼的只有GET超鏈接,因爲表單發送數據會默認使用URL編碼,也就是說,不用我們自己來編碼。

例如:“傳智”這兩個字通過URL編碼後得到的是:“%E4%BC%A0%E6%99%BA”。URL編碼是先需要把“傳智”轉換成字節,例如我們現在使用UTF-8把“傳智”轉換成字符,得到的結果是:“[-28,-68, -96, -26, -103, -70]”,然後再把所有負數加上256,得到[228, 188, 160, 230, 153, 186],再把每個int值轉換成16進制,得到[E4, BC, A0, E6, 99, BA],最後再每個16進制的整數前面加上“%”。

通過URL編碼,把“傳智”轉換成了“%E4%BC%A0%E6%99%BA”,然後發送給服務器!服務器會自動識別出數據是使用URL編碼過的,然後會自動把數據轉換回來。

 

當然,在頁面中我們不需要自己去通過上面的過程把“傳智”轉換成“%E4%BC%A0%E6%99%BA”,而是使用Javascript來完成即可。當後面我們學習了JSP後,就不用再使用Javascript了。

  <script type="text/javascript">
  	function _go() {
  		location = "/day05_2/AServlet?name=" + encodeURIComponent("傳智+播客");
  	}
  </script>
<a href="javascript:_go();">鏈接</a>

因爲URL默認只支持ISO-8859-1,這說明在URL中出現中文和一些特殊字符可能無法發送到服務器。

所以我們需要對包含中文或特殊字符的URL進行URL編碼。

服務器會自動識別數據是否使用了URL編碼,如果使用了服務器會自動把數據解碼,無需我們自己動手解碼。



發佈了39 篇原創文章 · 獲贊 52 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章