三月不減肥,五月徒傷悲,這就是我如今的狀態,哈哈~ 健身、博客堅持。html
--WZY瀏覽器
1、request請求參數出現的亂碼問題 tomcat
get請求:服務器
get請求的參數是在url後面提交過來的,也就是在請求行中,post
MyServlet是一個普通的Servlet,瀏覽器訪問它時,使用get請求方式提交了一個name=小明的參數值,在doGet中獲取該參數值,而且打印到控制檯,發現出現亂碼編碼
出現亂碼的緣由:url
前提知識:須要瞭解碼錶,編碼,解碼這三個名詞的意思。我簡單說一下常規的,spa
碼錶:是一種規則,用來讓咱們看得懂的語言轉換爲電腦可以認識的語言的一種規則,有不少中碼錶,IS0-8859-1,GBK,UTF-8,UTF-16等一系列碼錶,好比GBK,UTF-8,UTF-16均可以標識一個漢字,而若是要標識英文,就能夠用IS0-8859-1等別的碼錶。.net
編碼:將咱們看得懂的語言轉換爲電腦可以認識的語言。這個過程就是編碼的做用3d
解碼:將電腦認識的語言轉換爲咱們能看得懂得語言。這個過程就是解碼的做用
這裏只可以表明通過一次編碼例子,有些程序中,會將一個漢字或者一個字母用不一樣的碼錶連續編碼幾回,那麼第一次編碼仍是上面所說的做用,第二次編碼的話,就是將電腦可以認識的語言轉換爲電腦可以認識的語言(轉換規則不一樣),那麼該解碼過程,就必需要通過兩次解碼,也就是編碼的逆過程,下面這個例子就很好的說明了這個問題。
瀏覽器使用的是UTF-8碼錶,經過http協議傳輸,http協議只支持IS0-8859-1,到了服務器,默認也是使用的是IS0-8859-1的碼錶,看圖
也就是三個過程,經歷了兩次編碼,因此就須要進行兩次解碼,
一、瀏覽器將"小明"使用UTF-8碼錶進行編碼(由於小明這個是漢字,因此使用能標識中文的碼錶,這也是咱們能夠在瀏覽器上能夠手動設置的,若是使用了不能標識中文的碼錶,那麼就將會出現亂碼,由於碼錶中找不到中文對應的計算機符號,就可能會用??等其餘符號表示),編碼後獲得的爲 1234 ,將其經過http協議傳輸。
二、在http協議傳輸,只能用ISO-8859-1碼錶中所表明的符號,因此會將咱們原先的1234再次進行一次編碼,此次使用的是ISO-8859-1,獲得的爲 ???? ,而後傳輸到服務器
三、服務器獲取到該數據是通過了兩次編碼後獲得的數據,因此必須跟原先編碼的過程逆過來解碼,先是UTF-8編碼,而後在ISO-8859-1編碼,那麼解碼的過程,就必須是先ISO-8859-1解碼,而後在用UTF-8解碼,這樣就可以獲得正確的數據。????.getBytes("ISO-8859-1");//第一次解碼,轉換爲電腦可以識別的語言, new String(1234,"UTF-8");//第二次解碼,轉換爲咱們認識的語言
解決代碼
Post請求:
post請求方式的參數是在請求體中,相對於get請求簡單不少,沒有通過http協議這一步的編碼過程,因此只須要在服務器端,設置服務器解碼的碼錶跟瀏覽器編碼的碼錶是同樣的就好了,在這裏瀏覽器使用的是UTF-8碼錶編碼,那麼服務器端就設置解碼所用碼錶也爲UTF-8就OK了
設置服務器端使用UTF-8碼錶解碼
request.setCharacterEncoding("UTF-8"); //命令Tomcat使用UTF-8碼錶解碼,而不用默認的ISO-8859-1了。
因此在不少時候,在doPost方法的第一句,就是這句代碼,防止獲取請求參數時亂碼。
總結請求參數亂碼問題
get請求和post請求方式的中文亂碼問題處理方式不一樣
get:請求參數在請求行中,涉及了http協議,手動解決亂碼問題,知道出現亂碼的根本緣由,對症下藥,其原理就是進行兩次編碼,兩次解碼的過程
new String(xxx.getBytes("ISO-8859-1"),"UTF-8");
post:請求參數在請求體中,使用servlet API解決亂碼問題,其原理就是一次編碼一次解碼,命令tomcat使用特定的碼錶解碼。
request.setCharaterEncoding("UTF-8");
二、response響應回瀏覽器出現的中文亂碼。
首先介紹一下,response對象是如何向瀏覽器發送數據的。兩種方法,一種getOutputStream,一種getWrite。
ServletOutputStream getOutputStream(); //獲取輸出字節流。提供write() 和 print() 兩個輸出方法
PrintWriter getWrite(); //獲取輸出字符流 提供write() 和 print()兩個輸出方法
print()方法底層都是使用write()方法的,至關於print()方法就是將write()方法進行了封裝,使開發者更方便快捷的使用,想輸出什麼,就直接選擇合適的print()方法,而不用考慮如何轉換字節。
一、ServeltOutputStream getOutputStream();
不能直接輸出中文,直接輸出中文會報異常,
報異常的源代碼
解決:
resp.getoutputStream().write("哈哈哈,我要輸出到瀏覽器".getBytes("UTF-8"));
將要輸出的漢字先用UTF-8進行編碼,而不用讓tomcat來進行編碼,這樣若是瀏覽器用的是UTF-8碼錶進行解碼的話,那麼就會正確輸出,若是瀏覽器用的不是UTF-8,那麼仍是會出現亂碼,因此說這個關鍵要看瀏覽器用的什麼碼錶,這個就不太好,這裏還要注意一點,就是使用的是write(byte)方法,由於print()方法沒有輸出byte類型的方法。
二、PrintWriter getWrite();
直接輸出中文,不會報異常,可是確定會報異常,由於用ISO-8859-1的碼錶不能標識中文,一開始就是錯的,怎麼解碼編碼讀沒用了
有三種方法來讓其正確輸出中文
一、使用Servlet API response.setCharacterEncoding()
response.setCharacterEncoding("UTF-8"); //讓tomcat將咱們要響應到瀏覽器的中文用UTF-8進行編碼,而不使用默認的ISO-8859-1了,這個仍是要取決於瀏覽器是否是用的UTF-8的碼錶,跟上面的同樣有缺陷
二、通知tomcat和瀏覽器都使用同一張碼錶
response.setHeader("content-type","text/html;charset=uft-8"); //手動設置響應內容,通知tomcat和瀏覽器使用utf-8來進行編碼和解碼。
charset=uft-8就至關於response.setCharacterEncoding("UTF-8");//通知tomcat使用utf-8進行編碼
response.setHeader("content-type","text/html;charset=uft-8");//合起來,就是既通知tomcat用utf-8編碼,又通知瀏覽器用UTF-8進行解碼。
response.setContentType("text/html;charset=uft-8"); //使用Servlet API 來通知tomcaat和強制瀏覽器使用UTF-8來進行編碼解碼,這個的底層代碼就是上一行的代碼,進行了簡單的封裝而已。
三、通知tomcat,在使用html<meta>通知瀏覽器 (html源碼),注意:<meta>建議瀏覽器應該使用編碼,不能強制要求
進行兩步
因此response在響應時,只要通知tomcat和瀏覽器使用同一張碼錶,通常使用第二種方法,那麼就能夠解決響應的亂碼問題了
3、總結
在上面講解的時候老是看起來很繁瑣,其實知道了其中的原理,很簡單,如今來總結一下,
請求亂碼
get請求:
通過了兩次編碼,因此就要兩次解碼
第一次解碼:xxx.getBytes("ISO-8859-1");獲得yyy
第二次解碼:new String(yyy,"utf-8");
連續寫:new String(xxx.getBytes("ISO-8859-1"),"UTF-8");
post請求:
只通過一次編碼,因此也就只要一次解碼,使用Servlet API request.setCharacterEncoding();
request.setCharacterEncoding("UTF-8"); //不必定解決,取決於瀏覽器是用什麼碼錶來編碼,瀏覽器用UTF-8,那麼這裏就寫UTF-8。
響應亂碼
getOutputStream();
使用該字節輸出流,不能直接輸出中文,會出異常,要想輸出中文,解決方法以下
解決:getOutputStream().write(xxx.getBytes("UTF-8")); //手動將中文用UTF-8碼錶編碼,變成字節傳輸,變成字節後,就不會報異常,而且tomcat也不會在編碼,由於已經編碼過了,因此到瀏覽器後,若是瀏覽器使用的是UTF-8碼錶解碼,那麼就不會出現中文亂碼,反之則出現中文亂碼,因此這個方法,不能徹底保證中文不亂碼
getWrite();
使用字符輸出流,能直接輸出中文,不會出異常,可是會出現亂碼。能用三種方法解決,一直使用第二種方法
解決:通知tomcat和瀏覽器使用同一張碼錶。
response.setContentType("text/html;charset=utf-8"); //通知瀏覽器使用UTF-8解碼
通知tomcat和瀏覽器使用UTF-8編碼和解碼。這個方法的底層原理是這句話:response.setHeader("contentType","text/html;charset=utf-8");
注意:getOutputStream()和getWrite() 這兩個方法不可以同時使用,一次只能使用一個,不然報異常