1.JAVA WEB 筆記中文亂碼

来源:http://www.cnblogs.com/jtuzzzzZz/archive/2017/06/14/5899232.html
-Advertisement-
Play Games

JAVA WEB 亂碼問題解析 亂碼原因 在Java Web開發過程中,經常遇到亂碼的問題,造成亂碼的原因,概括起來就是對字元編碼和解碼的方式不匹配。 既然亂碼的原因是字元編碼與解碼的方式不匹配,那麼為什麼我們一定要對字元進行編碼,不編碼可不可以呢?這是因為在電腦中存儲數據的基本單位是1個位元組,即 ...


JAVA WEB 亂碼問題解析

亂碼原因

  在Java Web開發過程中,經常遇到亂碼的問題,造成亂碼的原因,概括起來就是對字元編碼和解碼的方式不匹配。

  既然亂碼的原因是字元編碼與解碼的方式不匹配,那麼為什麼我們一定要對字元進行編碼,不編碼可不可以呢?這是因為在電腦中存儲數據的基本單位是1個位元組,即8個bit,那麼它所能表達的字元的最多有28=256個,而在我們現實社會中存在的字元(漢字、英文、其他文字等等)遠遠多餘這個數字,所以為瞭解決字元與位元組的矛盾,對字元進行編碼處理才能存儲在電腦中。

編碼與解碼

  在電腦中常見的編碼方式有ASCII、ISO-8859-1、GB2312、UTF-16、UTF-8幾種編碼方式。

  ASCII碼是使用一個位元組的低7位來表示的,所以共能表達的字元最多有27=128個。ISO-8859-1是ISO組織基於ASCII碼的基礎上擴展來的,相容ASCII碼,涵蓋了大多數西歐字元。ISO8859-1使用一個位元組來表示,所以其能表達的字元最多有256個。GB2312,採用了雙位元組編碼,編碼範圍是A1-F7,其中A1-A9是符號區,B0-F7是漢字區,包含6763個漢字。GBK是為了擴展GB2312編碼,並加入了更多的漢字,總能表達的漢字有21003個。UTF-16是採用定長的編碼方式,無論什麼字元都採用2個位元組進行表示,這也是JAVA記憶體中字元的存儲格式。與UTF-16相反,UTF-8採用了變長的編碼方式,不同的類型的字元可以由1-6個位元組組成。

   下麵以字元串“日向雛田”來看一下在電腦中不同編碼方式的編碼,如下圖。

 

亂碼分析與解決

  對於JAVA WEB中亂碼問題,我們劃分位請求導致的亂碼和響應導致的亂碼,對於不同的亂碼我們要分析其亂碼原因,即字元編碼的方式是什麼,解碼的方式是什麼。

  對於由於請求導致的亂碼我們要分析Http請求,查看其編碼方式,由於HTTP請求分為Get請求和Post請求,我們接下來分別對其進行討論。

  對於Get請求,是瀏覽器預設的請求方式,和表單提交時設置為“Get”時的提交方式。我們通過火狐瀏覽器我們查看其具體內容如下:

  地址欄為:

  請求內容為:

  

  通過上面請求我們可以看到,GET請求中查詢字元串放在了請求行中存放,發送到WEB伺服器中,通過“日向雛田”編碼我們可以看到,瀏覽器對該字元串採用的編碼方式為“UTF-8”。

  查看伺服器代碼我們可以看到亂碼(如下圖),這是因為伺服器在接受到該字元串編碼後的數據預設通過ISO-8859-1的方式進行解碼,所以造成了編碼與解碼的方式不統一。

  

  解決方案如下:

  首先獲取字元串user解碼前的編碼,然後指定該字元串的編碼方式,如下圖:

  解決方案示意圖如下:

 

  在Java web開發過程中,我們在超鏈接中傳遞參數,經常遇到中文的情況。對此情況下,我們需要對中文進行編碼,我們可以設置為UTF-8,解碼方案同上。

  

<a href="${pageContext.request.contextPath}/Test?user=<%=URLEncoder.encode("日向雛田", "UTF-8")%>">點擊</a>

  對於Post請求,是表單提交時設置為“Post”時的提交方式。我們通過火狐瀏覽器我們查看其具體內容如下:

  地址欄及其頁面為:

  

  post請求內容為:

  

  由上圖我們可以知道,在post請求中,將請求內容直接放在請求體中發送給web伺服器,編碼方式為“utf-8”。

  在此響應Servlet中,doPost方法體如下:

  

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String user=request.getParameter("user");
		System.out.println(user);//輸出為日向雏田
	}

 

  此處亂碼的原因依然時在代碼getParameter(“user”)時,web伺服器採用預設的解碼方案“ISO-8859-1”進行解碼,導致了編碼與解碼方案的不同意,解決方案可以採用get請求亂碼的解決方案,但是還有一種更為簡單的解決方案,直接指定方法體的編碼/解碼方案為“utf-8”。方案如下。

  

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");  //設置請求體的編碼/解碼方案為UTF-8 但是請求行的編碼解碼方案不會受影響
		String user=request.getParameter("user");
		System.out.println(user);          //輸出為日向雛田
	}

   以上對於請求導致的亂碼情況分析完畢。

  在影響導致的亂碼中,web伺服器會將響應的內容寫入響應體中,返回給客戶端並不會涉及到狀態行中的情況。如向瀏覽器輸出”HelloWorld“其響應如下圖所說。

  對於響應導致的亂碼我們不得不涉及到四個方法,如下:

 

response.setHeader("Content-Type", "text/html;cahrset=utf-8");//設置發送到客戶端的響應的內容類型和響應內容的編碼類型(響應體的編碼類型)
response.setCharacterEncoding("utf-8");//設置響應體的編碼類型
response.getWriter();           //獲取響應的輸出字元流  response.getOutputStream();        //獲取響應的輸出位元組流

 

  對於設置響應體的編碼類型,如response.setHeader("Content-Type", "text/html;cahrset=utf-8");與response.setCharacterEncoding("utf-8");這2個方法設置的編碼方式等效,若沒有設置響應體的編碼方式,則預設為ISO-8859-1,而且後面設置響應體字元的編碼方式會迭代前面的設置編碼的方式。這兩個方法均在getWriter方法前有效,在getWriter方法設置編碼的方法會無效。

  但是這2個方法卻有點不同,即setHeader("Content-Type", "text/html;cahrset=utf-8")這個方法瀏覽器會自動採用該響應體的編碼方式進行解碼,而setCharacterEncoding()該方法並不是所有的瀏覽器都會採用該方法的編碼方式進行解碼,下麵對這2個方法進行測試,效果如下:

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setHeader("Content-Type", "text/html;charset=utf-8");
		response.getWriter().write("日向雛田");
	}

  

  

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.getWriter().write("日向雛田");
	}

  

 

   從上面可以看到第一個方法對於瀏覽器來說,支持的較好,提倡採用第一種方法設置響應體的字元編碼方式。

  對於獲取響應字元輸出流的方法,如果在此之前沒有設置響應體的編碼方式,那麼預設為null,即ISO-8859-1方式進行編碼。而且後面設置的編碼方式會覆蓋前面設置的編碼方式。在getWriter()方法之後設置的編碼無效。

  對於獲取響應輸出位元組流,我們在輸出字元串時,我們需要設置字元串的編碼方式如果沒有那麼預設ISO-8859-1。

  對於前面2個輸出流,由於只有一個輸出緩存,所以這兩個方法互斥。

  以上,為了保證響應無亂碼,需要保證字元編碼和解碼方法的統一,方案如下:

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
//	方案1
//		response.setHeader("Content-Type", "text/html;charset=utf-8");
//		response.getWriter().write("日向雛田");
//	方案2
//		response.getOutputStream().write("日向雛田".getBytes("UTF-8"));
//	方案1,2互斥
	}

  

   此外在Java web開發過程中,我們還會遇到當進行文件下載時,中文文件名導致的問題,如下圖所示:

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String realPath=this.getServletContext().getRealPath("/src/日向雛田.jpg");
		String fileName=realPath.substring(realPath.lastIndexOf('\\')+1);
		response.setHeader("content-disposition", "attachment;filename="+fileName);
		InputStream is=new FileInputStream(new File(realPath));
		OutputStream os=response.getOutputStream();
		byte[] buff=new byte[1024];
		int len=0;
		while((len=is.read(buff))>0){
			os.write(buff, 0, len);
		}
		os.close();
		is.close();
	}

  採用火狐瀏覽器進行測試,查看頁面效果,及其響應結果如下:

  

  經過查看響應頭分析,下載文件名存放在響應頭中,且對於中文文字沒有採用UTF-8、UTF-16、GBK等等能識別中文的編碼,那麼對於中文文件名導致採用哪種編碼方式呢?查看REF 7578得知,在此處採用ASCII編碼,但是REF規定,如果不可避免的要使用非ASCII碼的字元,程式員應該均勻的使用UTF-8,來最小化交互操作的問題。

  所以,解決方案就是把文件名編碼成UTF-8,傳遞給響應頭,瀏覽器(部分)預設對該文件名進行UTF-8解碼處理。

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String realPath=this.getServletContext().getRealPath("/src/日向雛田.jpg");
		String fileName=realPath.substring(realPath.lastIndexOf('\\')+1);
		String utf_8Name=URLEncoder.encode(fileName,"utf-8");//解決方案
		response.setHeader("content-disposition", "attachment;filename="+utf_8Name);
		InputStream is=new FileInputStream(new File(realPath));
		OutputStream os=response.getOutputStream();
		byte[] buff=new byte[1024];
		int len=0;
		while((len=is.read(buff))>0){
			os.write(buff, 0, len);
		}
		os.close();
		is.close();
	}

  效果如下:其中火狐瀏覽器並沒有對其解碼

  

 

文章最後欣賞老婆的美照:

    

 

  

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • HTTP協議: HTTP(Hypertext Transfer Protocol):即超文本傳輸協議。URL是通過HTTP協議存取資源的Internet路徑,一個URL對應一個數據資源。 HTTP協議對資源的操作: Requests庫提供了HTTP所有的基本請求方式。官方介紹:http://www. ...
  • 轉載:http://aguang520.iteye.com/blog/1056686 ...
  • 轉載請註明出處:http://www.cnblogs.com/Joanna-Yan/p/7010201.html 前面講到:Spring+SpringMVC+MyBatis深入學習及搭建(十二)——SpringMVC入門程式(一) 1.非註解的處理器映射器和適配器 1.1非註解的處理器映射器 前面我 ...
  • java字元串的功能可以說非常強大, 它的每一種方法也都很有用. java字元串中常用的有兩種字元串類, 分別是String類和StringBuffer類. Sting類 String類的對象是不可變的. 創建String 常用方法 實例: 比較性質的方法 查找方法 替換方法 其他方法 將數字化的字 ...
  • Python的Excel操作需要另外下載安裝對應Python版本的xlrd和xlwt包,用於對Excel的讀取和寫入。 安裝方法:直接解壓後,在字元命令界面cd到setup.py的目錄,執行命令“Python setup.py install”即可。 xlrd(下麵有些是方法,有些是屬性,屬性後面不 ...
  • 最近想學習一些python數據分析的內容,就弄了個爬蟲爬取了一些數據,並打算用Anaconda一套的工具(pandas, numpy, scipy, matplotlib, jupyter)等進行一些初步的數據挖掘和分析。 在使用matplotlib畫圖時,橫坐標為中文,但是畫出的條形圖橫坐標總是顯 ...
  • Java反射機制 前言 更多文章請一步本人博客 "https://chenjiabing666.github.io/" "網頁版的jdk的API" "離線版API" 什麼是反射機制 反射是java語言的一個特性,它允程式在運行時(註意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許 ...
  • 封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方法。 好處: 1.隱藏實現細節,提供公共的訪問方式。 2.提高了代碼的復用性。 3.提高了安全性。 封裝原則: 1.將不需要對外提供的內容都隱藏起來。 2.把屬性隱藏,提供公共方法對其訪問。 this:是當前類的對象引用。即:它就代表當前類的一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...