1. 程式人生 > >Java Web亂碼分析及解決方案(三)——響應亂碼

Java Web亂碼分析及解決方案(三)——響應亂碼

Java Web亂碼分析 -- 響應亂碼

響應亂碼

請求亂碼是客戶端向伺服器傳送資料時,伺服器解碼錯誤。響應亂碼則是伺服器處理完請求後,輸出到瀏覽器的資料被瀏覽器錯誤解碼造成的顯示亂碼,這類亂碼是最常見也是最直接的。

  • 造成這類亂碼大部分情況是:伺服器對Content-Type設定錯誤。

技巧和解決方案

出現亂碼時,定位方式技巧:

  • 首先確定瀏覽器實際使用的編碼和ContentType指定值是否一致;
  • 如果不一致,則調整Conent-Type值,看是否是瀏覽器不支援或者語法錯誤;
  • 如果一致,調整pageEncoding的值一般都可以解決亂碼的。

出現響應出現亂碼的解決方案,修改兩個地方:

  • 呼叫Response.setContentType設定MIME和字元編碼;
  • 修改頁面的HTML標籤,二者保持一致就可以了;
  • 對於靜態頁面要確定檔案儲存時的編碼和HTML標籤指定的編碼要一致;
  • 對於JSP檔案還要記得多調整一個pageEncoding。

Tomcat官方給出的建議:

  • 整個工程統一使用UTF-8作為字符集,它能在所有situation中都完美的工作,為了能徹底的使用UTF-8,你需要做如下的設定:
 (1)在server.xml的connector中設定URIEncoding=“UTF-8”;
 (2)使用Tomcat提供的CharsetEncodingFilter(和Spring MVC的差不多);
 (3)在JSP頁面的page指令中設定content-type=”text/html;charset=utf-8”; 或者jsp:directive.page contentType="text/html; charset=UTF-8";
 (4)在所有Servlet中都呼叫setContentType為“text/html;charset=utf-8”或者setCharsetEncoding方法設定Content-Type的編碼為UTF-8;
 (5)設定所有模板技術(比如FreeMarker、Velocity等)使用UTF-8,或明確的指定響應頭的Content-Type為UTF-8;
 (6)在你的字元編碼過濾器工作前,不要讓任何的其他Filter讀取Request的引數。

頁面資料亂碼分析

靜態頁面亂碼

靜態頁面:即我們用IDE編寫的頁面(比如.html),作為一個檔案,頁面在編寫的時候就需要指定一個字元編碼; 比如有些IDE預設的編碼格式是ISO-8859-1,此編碼是不支援中文字元的,檔案儲存時候即出現亂碼。

通常情況下,我們會有以下兩點規定:

  • 所有檔案統一使用UTF-8儲存檔案(unicode編碼的一種實現);
  • 頁面中設定meta標籤的Content-Type設定為UTF-8編碼就不會出現問題了。

動態頁面亂碼

動態頁面:程式動態輸出的頁面,比如模板技術、JSP、Servlet拼裝的頁面,這類技術一般都會保持一致的編碼,比如java用unicode,所以輸出的中文是沒問題的。

容易出現問題的地方就是我們沒有給瀏覽器設定編碼格式,即忘記設定Content-Type。

JSP頁面引數

使用JSP模板技術,有兩個引數影響編碼:pageEncoding和contentType。

pageEncoding

指定的是頁面編碼,該值編碼影響的是JSP檔案編譯為java和class檔案時,容器讀取JSP檔案內容時使用的編碼;

比如我們的JSP檔案用UTF-8儲存到本地磁碟,但是pageEncoding使用的是ISO-8859-1,JSP被預編譯為class檔案時會出現亂碼,JSP首先被翻譯拼接為Java檔案,讀取時IO流使用ISO-8859-1讀取檔案,發生亂碼;

contentType

指定瀏覽器解析頁面時應該使用的編碼;

這個值是給瀏覽器看的,可以認為是瀏覽器接收到資料後,IO流的讀取格式;

二者關係:

雖然pageEncoding和contentType的關係有點亂,但是一般來說它們的設定是有關聯的:

  • 一般二者的設定是聯動的,很多Web容器在設定了一個屬性後,另外一個屬性也會自動設定為一致的編碼值;
  • 在JSP中兩個值得預設值都是ISO-8859-1;
  • 實際開發時,我們都會把這兩個屬性值設定為一致的,如UTF-8;

Content-Type響應報頭

頁面在服務端構成之後,就要傳輸給瀏覽器了,這個時候伺服器會首先構建響應報頭;

大部分的響應報頭是容器自己處理的,我們無需關係,比如Content-Language、Content-Length等。

作用

Content-Type:告訴客戶端,Http響應包的實體主體是什麼媒體型別(MIME)。

Web瀏覽器通過Content-Type來確定用什麼模組處理響應的主體,同時通過附加的charset引數確定檔案的編碼型別,然後瀏覽器呼叫相應的模組和編碼方案解碼響應主體的檔案。

設定方式

在伺服器端通過呼叫response.setContentType()方法可以設定這個報頭的屬性。

注意,我們這裡討論的是HTTP協議,但是很多Web容器不會只支援HTTP協議,HTTP協議只是它的一種情況,所以會有很多奇怪的API和資料格式;

setContentType、setCharsetEncoding和setLocale 三者之間關係

  • setContentType:設定Content-Type值,可以順帶指定charset,順帶設定後,setCharsetEncoding可以不呼叫;
  • setCharsetEncoding:設定Content-Type的字元編碼部分,二者是覆蓋關係;
    • setContentType和setCharsetEncoding誰最後設定誰生效;
  • setLocale:設定的是Content-Language,國際化中設定區域,不重要,可以不理它,
    • 如果設定了Content-Type,Content-Language就失效了。

一般的響應頭格式如下:

content-type : text/html;charset=UTF-8

Java HttpServletResponse API

response的API開頭就有如下說明:

The charset for the MIME body response canbe specified explicitly using the setCharacterEncoding(java.lang.String) andsetContentType(java.lang.String) methods, or implicitly using thesetLocale(java.util.Locale) method. Explicit specifications take precedenceover implicit specifications. 

If no charset is specified, ISO-8859-1 will beused. The setCharacterEncoding, setContentType, or setLocale method must becalled before getWriter and before committing the response for the characterencoding to be used. See the Internet RFCs such as RFC 2045 formore information on MIME. Protocols such as SMTP and HTTP define profiles ofMIME, and those standards are still evolving.

翻譯後的大概意思:

影響Response Body的字元編碼的方法有三個,setContentType、setCharsetEncoding以及setLocale。 

Tomcat官方給出的建議:

What canyou recommend to just make everything work? (How to use UTF-8 everywhere). Using UTF-8 asyour character encoding for everything is a safe bet. This should work forpretty much every situation.

In order to completelyswitch to using UTF-8, you need to make the following changes:

1.Set URIEncoding="UTF-8" onyour in server.xml.References: HTTPConnector, AJPConnector.

2.Use a characterencoding filter withthe default encoding set to UTF-8;

3.Change all your JSPs to include charset name in their contentType.

For example, use <%@page contentType="text/html; charset=UTF-8" %> forthe usual JSP pages and forthe pages in XML syntax (aka JSP Documents).

4.Change all your servlets to set the content type for responses and to include charset name in the content type to be UTF-8.Use response.setContentType("text/html;charset=UTF-8") or response.setCharacterEncoding("UTF-8").

5.Change any content-generation libraries you use (Velocity, Freemarker, etc.) to use UTF-8 and to specify UTF-8 in the content type of the responses that they generate.

6.Disable any valves or filtersthat may read request parameters before your character encoding filter or jsppage has a chance to set the encoding to UTF-8. For more information see http://www.mail-archive.com/[email protected]/msg21117.html.

附註——Response的API

response.setContetType

Sets the content type of the response beingsent to the client, if the response has not been committed yet. The givencontent type may include a character encoding specification, for example, text/html;charset=UTF-8.The response's character encoding is only set from the given content type ifthis method is called before getWriter is called.

This method may be called repeatedly tochange content type and character encoding. This method has no effect if calledafter the response has been committed. It does not set the response's characterencoding if it is called after getWriter has been called or after theresponse has been committed.

Containers must communicate the content typeand the character encoding used for the servlet response's writer to the clientif the protocol provides a way for doing so. In the case of HTTP, the Content-Type headeris used.

翻譯: 

如果response還沒有發生,那麼在傳送response給客戶端之前設定response的content type,設定的content type可以包含字元編碼,比如:text/html;charset=UTF-8。如果在getWriter被呼叫之前呼叫了這個方法,那麼response的編碼將會根據給定的content type設定。

這個方法可以被重複的呼叫來改變content type和字元編碼。如果在response提交之後呼叫,這個方法是無效的。如果在getWriter被呼叫之後或response提交之後呼叫這個方法,對response字元編碼的設定也不會起作用。

如果協議提供了和客戶端通訊的content type的方式,那麼容器將使用response的wirter向容器傳送關於content type和字元編碼的資訊。在http協議下使用的是Content-Type報頭。

reqponse.setCharsetEncoding

Sets the character encoding (MIME charset)of the response being sent to the client, for example, to UTF-8. If thecharacter encoding has already been set by setContentType(java.lang.String) or setLocale(java.util.Locale),this method overrides it. Calling setContentType(java.lang.String) withthe String of text/html and calling this method with the String of UTF-8 isequivalent with calling setContentType with the String of text/html;charset=UTF-8.

This method can be called repeatedly tochange the character encoding. This method has no effect if it is called after getWriter hasbeen called or after the response has been committed.

Containers must communicate the characterencoding used for the servlet response's writer to the client if the protocolprovides a way for doing so. In the case of HTTP, the character encoding iscommunicated as part of the Content-Type header for text media types.Note that the character encoding cannot be communicated via HTTP headers if theservlet does not specify a content type; however, it is still used to encodetext written via the servlet response's writer.

翻譯:

在response被髮送給客戶端之前,設定字元編碼型別(MIME的字元),例如,使用“UTF-8”編碼。如果字元編碼已經通過setContentType或者setLocale設定了,這個方法將會覆蓋他們。下面的呼叫是相等的,呼叫setContentType設定content Type為text/html,呼叫setCharsetEncoding設定字元編碼為UTF-8,等同於呼叫setContentType設定content Type為text/html;charset=utf-8

可以重複呼叫這個方法,但是必須在getWriter之前或者response被提交之前。

容器會把字元編碼告訴客戶端,如果協議提供了相應的通訊方式。在HTTP協議下,字元編碼作為Content –Type報頭的一部分提供給客戶端。值得注意的是如果servlet沒有指定content type,那麼字元編碼將不會通過Http協議傳送給客戶端,但是傳送給客戶端的文字仍然會用給定的字符集編碼。


相關推薦

Java Web亂碼分析解決方案——響應亂碼

Java Web亂碼分析 -- 響應亂碼 響應亂碼 請求亂碼是客戶端向伺服器傳送資料時,伺服器解碼錯誤。響應亂碼則是伺服器處理完請求後,輸出到瀏覽器的資料被瀏覽器錯誤解碼造成的顯示亂碼,這類亂碼是最常見也是最直接的。 造成這類亂碼大部分情況是:伺服器對Content-T

Java Web亂碼分析解決方案——GET請求亂碼

引言: 在進行Web開始時,亂碼是我們最經常遇到也是最基本的問題,有經驗的程式猿很容易能解決,初學者則容易被泥潭困住。而且很多時候,我們即使解決了亂碼問題也是不明就裡,往往雲裡霧裡。 其實亂碼問題很簡

Java Web亂碼分析解決方案——POST請求亂碼

引言     GET請求的本質表現是將請求引數放在URL位址列中,form表單的Method為GET的情況,引數會被瀏覽器預設編碼,所以亂碼處理方案是一樣的。對於POST請求亂碼,解決起來要比GET簡單,我們關心的重點是在Request Body中。 請求亂碼——Meth

Python の TypeError 解決方案

Something about Format Character (關於格式符の那些事~)鍵入如圖所示程式碼 , 第一行成功打印出結果,第二行出現TypeError :解析:type(g) 即 g的型別為 string (即圖中提到的str) , 不管用list() 、tup

ionic開發常見問題解決方案

1 .如何生成應用圖示與啟動頁面背景:安卓與iOS a.進入resources資料夾; b.把resources目錄下預設的icon(應用圖示)和splash圖示(啟動介面圖示)換成當前APP對應的圖示; c.把resources目錄下android和ios資料夾刪

[Web 前端] mobx教程(五)-Mobx常見問題解決方案1Mobx使用嚴格模式

copy from : https://blog.csdn.net/smk108/article/details/83185745 mobx在嚴格模式下,不允許在 action 外更改任何狀態。但是不同版本嚴格模式的用法不同,3.x、4.x、5.x三個版本下的嚴格模式用法。 1、[email&#

Java WEB安全問題解決方案

1.弱口令漏洞 解決方案:最好使用至少6位的數字、字母及特殊字元組合作為密碼。資料庫不要儲存明文密碼,應儲存MD5加密後的密文,由於目前普通的MD5加密已經可以被破解,最好可以多重MD5加密。 2.未使用使用者名稱及密碼登入後臺可直接輸入後臺URL登入系統。 解決方

Uber使用Swift重寫APP的踩坑經歷解決方案轉載

result 框架 退出 帶來 hole 懶漢 將在 例子 穩定 本文出自Uber移動架構和框架組負責人托馬斯·阿特曼於2016年在灣區Swift峰會上的演講,分享了使用Swfit重寫Uber的好與壞。以下為譯文: 我是托馬斯·阿特曼,目前是Uber移動架構和框架組負責人。

java.lang.IllegalArgumentException java.sql.Date.getHours的解決方案SSH

問題描述: Caused by: java.lang.IllegalArgumentException at java.sql.Date.getHours(Date.java:143) 這是由於於java.util.Date 和 java.sql.Date的轉換問題造

Matrikon OPC常見問題解決方案

本文主要分享了使用MatrikonOPC伺服器時遇到的一些最常見的問題和相應的解決方案。 在聯絡MatrikonOPC支援團隊之前,你可以看一下以下問題/解決方案和問題/答案部分是否能幫助你解決目前問題。 問題和解決方案 安裝時出現“aprxdist”錯誤 問題 安裝

go語言,第三方包相對路徑匯入包引起的問題解決方案goquery

對go語言而言,跟蹤init很顯然包有且僅有一次被匯入的可能。 但是重複引用了goquery包,後編譯出現問題  專案涉及相關目錄 ├── main.go└── parse    └── parse.go parse包和main.go都匯入了 goquery包 main

Jenkins入門教程之自動構建部署專案常見錯誤解決方案jenkins中構建maven專案一直打包失敗

此篇文章總結六筆者在使用jenkins過程中的一些坑和常見錯誤總結和解決方案,在這裡分享給大家,希望大家少走彎路。常見錯誤:1、在 Jenkins 中,使用 maven 打包報 package xxx does not exist 問題的解決方法錯誤資訊:解決方案:需要把ma

Python の TypeError 解決方案

1、TypeError : argument of type 'int' is not iterable   型別'int'的引數不可迭代Python (3.7.14)中鍵入如下程式碼:為了判斷1是否在list中。1)採用成員操作符 in ,返回Bool 型別的值。(True

開發中遇到的bug解決方案

該異常表示不能新增視窗,通常是所要依附的view已經不存在導致的。[解決方案]:Dialog&AlertDialog,WindowManager不能正確使用時,經常會報出該異常,原因比較多,幾個常見的場景如下:1.上一個頁面沒有destroy的時候,之前的Activity已經接收到了廣播。如果此時之前

java-Web對於反射的支援+ClassLoader-非重點

Web對於反射的支援 非重點: 在我們現在的開發之中,假設迴歸到模式一的時代,那麼這個過程裡面重點就是JSP+JavaBean的時代,那麼在這種模式下,使用者需要接受請求的引數,然後將其變成簡單java類,而這一過程JSP本身就已經做了優化。l在JSP裡面提

使用訊息佇列實現分散式事務-公認較為理想的分散式事務解決方案

  Begin transaction update A set amount=amount-10000 where userId=1; update B set amount=amount+10000 where userId=1; End t

JS元件系列——BootstrapTable+KnockoutJS實現增刪改查解決方案:兩個Viewmodel搞定增刪改查

前言:之前博主分享過knockoutJS和BootstrapTable的一些基礎用法,都是寫基礎應用,根本談不上封裝,僅僅是避免了html控制元件的取值和賦值,遠遠沒有將MVVM的精妙展現出來。最近專案打算正式將ko用起來,於是乎對ko和bootstraptable做了一些封裝,在此分享出來供園友們參考。封裝

移動端相容性問題解決方案

1. IOS移動端click事件300ms的延遲響應移動裝置上的web網頁是有300ms延遲的,玩玩會造成按鈕點選延遲甚至是點選失效。這是由於區分單擊事件和雙擊螢幕縮放的歷史原因造成的,2007年蘋果釋出首款iphone上IOS系統搭載的safari為了將適用於PC端上大螢幕的網頁能比較好的展示在手機端上,使

企業級自定義表單引擎解決方案--實體物件模型設計

  自定義表單設計的目標是不編寫程式碼,由設計人員在介面設計表單配置,使用者就能使用具體的功能模組了,對於這個目標,首先要解決的就是資料儲存以及資料庫與表單之間的對映問題。   平時如果使用過程式碼生成工具,應該對大體的過程有些認識。要麼從資料庫讀取已經定義好的表結構,工具生成實體部分程式碼,或者是與框架強相

企業級自定義表單引擎解決方案--實體物件模型實現

實體物件模型與資料庫對應實現   主要是解決實體物件模型與資料庫之間的一一對應,在介面上新增實體物件模型,增加欄位,則同步管理業務實體資料庫表結構,主要的思路就是介面上修改了實體模型,同步執行修改資料庫表結構的Sql語句(已經運行了一段時間的業務表,需要DBA實現修改資料庫再修改實體模型),介面大概如下: