溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Web開發(fā)亂碼問題原理分析

發(fā)布時間:2020-06-13 02:53:22 來源:網絡 閱讀:957 作者:anranran 欄目:開發(fā)技術

Java web開發(fā)過程經常遇到亂碼,本篇我們探討一下亂碼產生的原因與解決思路。

一次完整的Web請求會有4次編解碼轉換,如下所示。

 

第一次:客戶端(通常為瀏覽器)將字符轉換成TCP字節(jié)流發(fā)向服務器。

這里有一次字符到字節(jié)的轉換。

第二次:服務器讀取客戶端發(fā)來的TCP字節(jié)流,轉換成字符串。

這里是一次字節(jié)到字符的轉換。

第三次:服務器將結果字符串換成TCP字節(jié)流發(fā)向客戶端。

這里又有一次字符到字節(jié)的轉換。

第四次:客戶端讀取服務端發(fā)過來的響應字節(jié)流。轉換成字符串顯示。

Web開發(fā)亂碼問題原理分析

一個完整的Web請求就結束了。

 

聰明的你已經發(fā)現(xiàn)了,第一次轉換和第二次轉換是一對對應的編解碼。第三次和第四次轉換是一對對應的編解碼。也就是第一次會哪種字符集編碼,第二次就要用相同的字符集解碼。

第三次可以選擇與前兩次不同的字符集,但第四次必須第三次相同。不錯,你已經入門了。

 

我們怎么找到第一次的編碼的字符。Web客戶端程序的作者定然知道他用什么字符發(fā)送Web請求,我們就不多說了。我們這里只說瀏覽器,因為絕大數(shù)請求是瀏覽器發(fā)出來的。

 

瀏覽器在提交post或get表單時,采用是瀏覽器當前頁面的編碼。

查看chrome瀏覽器、360極速瀏覽器等當前頁面編碼:點擊瀏覽器右側菜單圖標,然后依次將鼠標移到“工具”→“編碼”即可查看或更改當前頁面的編碼模式。

而當前頁的編碼是當瀏覽器獲取該頁面時,第四次轉換決定的。瀏覽器是根據(jù)響應頭和響應正文決定采用哪種編碼。

發(fā)現(xiàn)沒有,上面我們說到第一次轉換決定了第二次轉換的編碼,第三次決定了第四次轉換的編碼。而這里第四次又決定第一次轉換的編碼。一個環(huán)形轉換形成了。

A1=A2, A3=A4, A4=A1所以A1=A2=A3=A4. 證明選擇相同的字符是完成正確編碼的轉換的充分條件。

 

說完了第一次編碼,我們講一下第二次解碼。

客戶端發(fā)過的請求報文,分三部分: 請求行,請求頭,POST正文。存在亂碼可能的位置有兩個地方,請求URL的參數(shù)部分和POST正文。(英文字符為什么沒亂碼? 因為采用ASCII碼,絕大部分字符集對英文的編碼都一樣的)。

服務器在解析這兩部分時,分別有自已的字符集。拿Tomcat來說,urlEncoding參數(shù)指定解析URL參數(shù)部分的編碼。而request.getCharsetEncoding()指定的是解析POST正文的字符集。

 

說完第二次解碼,說一下第三次的編碼。

服務端將字符發(fā)向客戶端,必須轉換成字節(jié)流。用什么編碼好呢? JSP頁面有兩個設置選項:pageEncodingcontentType。你注意到了嗎?

一般情況他們都會同時出現(xiàn)。pageEncoding表示是JSP文件的編碼,而contentType是服務端將字符發(fā)向客戶端的字符集編碼。這個字符集會寫在響應報文頭的Content-Type字段中的。Content-Type:"text/javascript;charset=gbk"。只有contentType存在,好理解。pageEncoding的出現(xiàn),與contentType有了點情感糾葛。記得是一點。大家知道JSP文件需要編譯成Java文件. 

這個過程:1. 讀取JSP文件,2. 轉換Java類字符串,3.寫入JAVA文件。文件都是字節(jié)流。讀取JSP文件就是采用pageEncoding字符集來解碼。寫入JAVA的編碼一律為UTF-8(因為JAVAC用UTF-8去編譯java到class).

 

這一點情感糾葛就在,contentType不存在時候,pageEncoding字符集會代替他。

 

下面第四次是在瀏覽器顯示最終結果的時候。

瀏覽器采用響應頭中的Content-Type字段來解析響應報頭,并顯示。

如果Content-Type不存在,則瀏覽器會采用:
<meta http-equiv=Content-Type content="text/html;charset=gb2312"> 

指定的字符集來解碼。

 

完了,聽上去好像很簡哦,但為什么會出現(xiàn)那么多亂碼的情況?常見情況:

  1. AJAX請求。

AJAX請求的編碼是程序設定的。不在A1到A4這環(huán)形家庭中。程序

員沒能理解各個編碼參數(shù)作用點,所以出錯,由上面4步的分析。如果還不能理解,我只能呵呵。

  1. urlEncoding各平不一樣。

Post正文是由request.getCharsetEncoding()字符集解析,這個字符集是程序控制的。URL的請求參數(shù)是由urlEncoding字符集解析的。而urlEncoding一般由服務器設定不一樣,比如Tomcat默認為iso8859-1。遷移過程中注意這個。

 

  1. JSP文件保存格式不對。

JSP中pageEncoding指定為GBK,JSP文件卻保存成UTF-8,轉換就成亂碼了。后續(xù)不用看,肯定亂。解決亂碼問題一定要先排除這個問題。

 

  1. 編碼不統(tǒng)一。

一個項目幾種編碼,什么樣的團隊呀。子系統(tǒng)內部可以,一跨界,完蛋。

 

如果出現(xiàn)亂碼,怎么排查?

 

一般二分法,看看服務端顯示是不是正確的,一般將參數(shù)System.out輸出到Console或者日志(一定要注意日志文件你打開時的編碼,本來輸出是對的,你反而打開亂了)。

如果能看到正確字符串,一般是第三次或第四次轉換不正確,如果看到亂碼,前二次轉換不正確。第二種情況為絕大多數(shù),因為前一種情況,程序員的參與度很小。

我只說第二種情況:

  1. 首先確定是URL參數(shù),還是POST參數(shù)亂碼。

  2. 根據(jù)1獲取urlEncoding或request.getCharsetEncoding.

  3. 通過查看瀏覽器,或通過httpwatch或tcpdump等工具來確定客戶端請求的編碼。在我國基本上GBK,UTF-8。UTF-8基本用3個字節(jié)表示中文,GBK用兩處,很好區(qū)分。

  4. 改成一致就好了。

                                              2016-12-24夜,蘇州


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI