1. 程式人生 > >Java Web中常見亂碼問題的分析與解決

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方式提交引數的編碼方式。

3Meta標籤中的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頁面中,中文顯示亂碼

總結

開發時應注意工作區編碼,前端編碼,伺服器編碼,資料庫編碼一致。

造成亂碼的原因就是因為使用了錯誤的字元編碼去解碼位元組流因此當我們在思考任何跟文字顯示有關的問題時,請時刻保持清醒:當前使用的字元編碼是什麼