1. 程式人生 > >tomcat中的字符集問題,測試以及總結(HTTP請求響應)

tomcat中的字符集問題,測試以及總結(HTTP請求響應)

HTTP伺服器的通常作用可以理解成,接收來自瀏覽器的請求,讀取其中的資訊,並返回http格式的資料

其中,瀏覽器傳送的資料主要以三種形式傳遞,get方式提交的引數,post方式的引數,以及cookie中攜帶的引數三類

而伺服器端,生成http返回資料的形式主要有3種

其中,JSP在本質上與Servlet無異,一般可認為JSP在Servlet的基礎上,加上了Html的框架,不過如果把JSP程式碼中的HTML程式碼去掉,兩者基本就是一個東西了。

整個流程中,需要注意到字符集的動作,巨集觀而言,分為四步:

字符集問題出現在資訊從一級流通到另一級的過程中,也就是這4個動作當中。要規避字符集問題,需要了解四個動作中,分別的,其使用的字符集的確認方式。

主要包括,a中資料編碼採用何種字符集,b中如何確認解析時用的字符集,c中如何確定採用的字符集,d中如何確認解析時所用的字符集

以下就這四個問題展開討論

1、瀏覽器傳送資料時,採用哪種字符集?

瀏覽器發起一個請求,需要通過URL訪問

根據形式分為,直接在瀏覽器中輸入URL訪問,以及通過連結跳轉訪問,通過連結跳轉訪問則包括form表單以及超連結兩種形式

而無論哪種形式,最終瀏覽器都會將其包裝成HTTP格式進行訪問,也即如下格式:

POST /MyTestProject6/Test_Servlet_002 HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 39
Cache-Control: max-age=0
Origin: http://localhost
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost/MyTestProject6/Test_003.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=1420F43C4B8259D6FCCD46E87B095DB3; _ga=GA1.1.1822121407.1535547634

request資訊中,並不會指定編碼集。

那引數在傳遞過程中,對中文進行編碼的格式如何確定呢?

分兩種,直接在URL欄中輸入的中文,會以瀏覽器預設的編碼集進行編碼。

 如此去訪問,火狐瀏覽器的結果是:

chrome瀏覽器的結果也是:

而其他的的訪問,也即是由頁面生成的URL,其內容的編碼格式取決於該頁面在編碼時使用的字符集

一定程度上,也就是頁面中的<meta charset="XXX">標籤,該標籤標註了該頁面的編碼格式

(不過會有特例,之後會進行說明)

當頁面中<meta charset="XXX">標籤預設時。瀏覽器會採用預設字符集對頁面進行編譯,這也是由這個頁面所產生的URL在生成request時所採用的字符集。

總結:瀏覽器傳送資料時,採用哪種字符集?

1、直接輸入URL的,依瀏覽器(chrome:utf-8,火狐:gbk)

2、頁面採用何種字符集編碼,則傳送資料時採用何種字符集

3、頁面未制定字符集時,chrome和火狐都預設使用GKB進行編碼

2、伺服器解析瀏覽器傳送的資料時,使用何種字符集?

上文提到,request中並不會攜帶關於request的內容由哪種字符集資訊。

因此,伺服器在解析資料時,隨緣。。。

比如某個使用者在URL中自己手動輸入中文引數,可能會影響。

但大多數URL都由伺服器自身的頁面發出,統一字符集的話,一般不會受到字符集問題的影響。

以下,以TOMCAT9為例,闡述如何應對GET請求,POST請求的處理方式。

總所周知,一條URL請求,會由瀏覽器包裝成HTTP格式,再發送到伺服器,因此伺服器接受到的資料是一個數據包,而非單單一個URL字串。

其中訪問路徑資訊path在第一行的中間,並且以get形式提交的資料顯示在了path當中。

tomcat7以上的版本,對於path的內容,會自動用utf-8去解碼。其也可以在server.xml中去配置。

而tomcat7以及以下的版本,預設的字符集依然是iso-8859-1。因此需要通過對應的格式去decode。

不過TOMCAT9自動預設UTF-8也有不好的地方,get請求的引數預設就直接UTF-8編碼了,也就是無論GBK還是UTF-8傳送過來都成了UTF-8。也就無法讀取GET裡面的內容了

而POST請求,TOMCAT並不會自動解碼,而預設的字符集是iso-8859-1,只需要設定其為對應的字符集即可。

總結:伺服器解析瀏覽器傳送的資料時,使用何種字符集?

可以設定,一般預設iso-8859-1,tomcat7以上get請求預設utf-8

3、伺服器返回資料時,使用何種字符集?

 伺服器返回http資料時,一般有三種方式。

其中servlet中直接在response寫入的方式不難得出

如果未設定contentType,瀏覽器會使用預設的iso-8859-1進行解析

如果設定了contentType,比如:

response.setContentType("text/html;charset=utf-8"); response.getWriter().append("測試直接傳輸一箇中文");

 則瀏覽器會使用對應的字符集進行解析。

BUT,需要注意的是,最終傳輸的資料的字符集需要與此時設定的字符集保持一致。

不一致的情況包括而不限於:

比如上述程式碼的.java檔案字符集是其他的,比如

而程式碼中設定的字符集為UTF-8,因此最終頁面會亂碼

這也是JSP跟HTTP頁面中需要注意的

在HTML頁面中,主要通過<meta charset="xxx"> 來控制頁面使用的字符集。

<!DOCTYPE html>
<html>
<head>
<meta charset="gbk">
<title>Insert title here</title>
</head>
<body>
    中文
</body>
</html>
HTTP/1.1 200
Accept-Ranges: bytes
ETag: W/"300-1536840847318"
Last-Modified: Thu, 13 Sep 2018 12:14:07 GMT
Content-Type: text/html
Content-Length: 300
Date: Thu, 13 Sep 2018 12:14:10 GMT

不難看出,在訪問HTTP頁面時,其response的頭中,根本沒有標註其所使用的字符集

可以理解成,伺服器在響應返回html頁面時,並不會對其內容進行解析,而是直接傳送過去,因此伺服器也不知道該html的字符集

而瀏覽器在接收到response相應之後,也是在讀取response的content部分中的meta標籤才確定字符集。

HTML檔案同樣需要注意,最終傳輸的資料的字符集需要與此時設定的字符集保持一致。

預設時,chrome和火狐都預設使用gkb編碼(應對contentType為text/html)

在JSP檔案中,可以設定的字符集格式檔案包括pageEncoding,contentType,以及其html程式碼中的meta標籤。

不過contentType可以預設,contentType預設時伺服器會根據pageEncoding設定contentType中的charset。

比如:

<%@page pageEncoding="utf-8"%>
這是一箇中文
HTTP/1.1 200
Content-Type: text/html;charset=utf-8
Content-Length: 22
Date: Thu, 13 Sep 2018 12:22:49 GMT

而如果在已經有pageEncoding的情況下再去設定contentType的charset,後者會覆蓋前者,比如:

<%@page contentType="text/html;charset=gbk" pageEncoding="utf-8"%>
這是一箇中文
HTTP/1.1 200
Content-Type: text/html;charset=gbk
Content-Length: 16
Date: Thu, 13 Sep 2018 12:24:04 GMT

當contentType設定了時,pageEncoding可以預設,此時會預設使用contentType中設定的字符集作為pageEncoding的字符集。

此時依然需要注意,最終傳輸的資料的字符集需要與此時設定的字符集保持一致。

但此時,如果字符集衝突,其衝突是在JSP的編譯階段,而不是在瀏覽器上的顯示階段。

比如,當我設定了pageEncoding,但是跟.jsp檔案採用的字符集不同時,其結果是在編譯而成的.java檔案中就出現了亂碼

 比如

<%@page pageEncoding="utf-8"%>
這是個中文

則訪問亂碼

 其.java檔案中就已經出現了亂碼

  response.setContentType("text/html;charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("���Ǹ�����\r\n");

當pageEncoding和contentType都預設時,JSP編譯器會很暈。。然後用iso-8859-1編碼

總之!!就是不用meta裡面設定的字符集。。。

<%@page%>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>Insert title here</title>
</head>
<body>我是個中文
</body>
</html>

HTTP/1.1 200
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 136
Date: Thu, 13 Sep 2018 12:34:10 GMT

總結:伺服器返回資料時,使用何種字符集?

1、servlet端需要設定contentType,注意與程式碼的編碼檔案格式保持一致,預設時瀏覽器使用iso-8859-1。

2、html檔案需要設定<meta charset>,注意與html檔案的編碼格式保持一致,預設時瀏覽器使用gbk。

3、jsp檔案需要設定contentType或pageEncoding,注意與jsp檔案的編碼格式保持一致,預設時瀏覽器使用gbk,但JSP編譯器會通過iso-8859-1去編譯。

4、瀏覽器解析資料時,採用何種字符集

 依照上文

瀏覽器在解析時使用的字符集,依照response的head中的引數。

總結:

1、當預設時,若返回的contentType為text/html,則火狐和chrome都會使用GBK編碼

2、若contentType預設,則會使用iso-8859-1編碼。