Java Web中常見亂碼問題的分析與解決
Java Web中出現亂碼的現象:
第一類:前臺引數傳輸至服務端後亂碼
1. get請求引數中文傳送到伺服器端亂碼
2. post請求引數中文傳送到伺服器亂碼
第二類:服務端響應到達瀏覽器後亂碼
3. 在jsp頁面中,中文顯示亂碼
Java Web中出現的各種編碼:
1. JSP檔案自身的編碼
Jsp檔案中會出現下面所示的編碼指定方式:
<%@ page language=“java” contentType=“text/html; charset=UTF-8″ pageEncoding=“UTF-8″%>
<meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8″>
1)pageEncoding="utf-8" --該jsp檔案自身採用的編碼格式,也就是告訴伺服器使用什麼編碼翻譯jsp檔案成java檔案
jsp中post表單的編碼由pageEncoding和contentType引數決定,以pageEncoding為準,如果沒有pageEncoding則以contentType為準,如果沒有contentType以Meta標籤中的charset為準,都沒有則以ISO-8859-1編碼
2)contentType="text/html;charset=utf-8"伺服器傳送瀏覽器的資料型別和內容編碼。其中charset="utf-8"--用來指定Tomcat返回響應時採用的編碼,也是post方式提交引數的編碼方式。
3)Meta標籤中的charset是在contentType未指定編碼時採用的預設編碼格式
2. Tomcat讀取JSP檔案時採用的編碼
參考1)
3. Tomcat返回響應時採用的編碼
參考2)
4. 瀏覽器顯示HTML時採用的編碼
瀏覽器的編碼格式的設定
根據現象分析解決方案:
1. get請求引數亂碼
2. post請求引數亂碼
POST表單引數是通過http的body傳遞到伺服器的。前面已經說過,表單項引數是採用contentType中的charset指定的編碼格式進行編碼的。伺服器端也是用contentType中的charset指定的編碼進行解碼操作,所以一般不會出現亂碼問題。
這個編碼我們可以通過request.setCharacterEncoding()來進行設定,該設定只對POST引數有效。注意,這個函式必須在第一次呼叫request.getParameter()之前使用。
3. 同時處理Get和Post兩種提交方式的編碼問題
GET和POST兩種方式的不同表現使得處理起來比較麻煩。
根據1和2,使用組合方法可以確定多種解決策略。
解決方案1:分別處理get和post請求
處理get請求:在Tomcat的server.xml下的connector屬性中新增引數URIEncoding=’UTF-8’;
處理post請求:在Servlet中設定request.setCharacterEncoding()
解決方案2:都使用手動重新解碼
以上兩種方式存在一個共同的問題,那就是隻要請求中有中文,每一個servlet都要進行重複的處理。應該抽取出這個過程。
解決方案3:使用引數useBodyEncodingForURI=’true’
在Tomcat的server.xml下的connector屬性中新增引數useBodyEncodingForURI=’true’(注意,並不是對整個URI都採用BodyEncoding,只是應用於Query String而已)。這樣,Tomcat便會用request.setCharacterEncoding()指定的編碼來解析GET引數了。
解決方案4:使用過濾器Filter並運用動態代理實現編碼統一處理
package EncodingFilter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
// 如果希望匿名內部類使用一個在外部定義的物件,那麼編譯器會要求其引數引用是final的
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
request.setCharacterEncoding("UTF-8");// POST提交有效
response.setContentType("text/html;charset=UTF-8");
// 解決:對HttpServletRequest介面的getParameter方法進行功能擴充套件,識別GET請求,可以使用動態代理!
HttpServletRequest proxyRequest = (HttpServletRequest) Proxy.newProxyInstance(request.getClass().getClassLoader(),
new Class[] { HttpServletRequest.class },
new InvocationHandler() {
// args物件陣列,代表被呼叫方法的引數
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
String methodName = method.getName();
if ("getParameter".equals(methodName)) {
String value = request.getParameter(args[0]
.toString());
String requestMethodName = request.getMethod();
if ("GET".equals(requestMethodName)) {
// 不為空 也不為 空字串
if (value != null && !"".equals(value.trim())) {
value = new String(value
.getBytes("iso-8859-1"), "utf-8");
}
}
return value;
} else {
return method.invoke(request, args);
}
}
});
//放行 (執行下一個過濾器或者servlet)
chain.doFilter(proxyRequest, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
再在web.xml中配置filter和filter-mapping,搞定
4. 伺服器傳送給瀏覽器的亂碼問題
5. 在jsp頁面中,中文顯示亂碼
總結
開發時應注意工作區編碼,前端編碼,伺服器編碼,資料庫編碼一致。
造成亂碼的原因就是因為使用了錯誤的字元編碼去解碼位元組流,因此當我們在思考任何跟文字顯示有關的問題時,請時刻保持清醒:當前使用的字元編碼是什麼。