用戶發送 HTTP 請求 → 瀏覽器對 URL、Cookie、Parameter 編碼 → 服務器接收並解析 → 對 URL、Cookie、Parameter 解碼 → 業務邏輯處理(涉及數據庫、文件等編解碼) → 服務器編碼響應 → 瀏覽器解碼顯示。最易發生亂碼的環節在於客戶端與服務器的交互過程。
scheme://host:port/path?queryString。瀏覽器會對 path 和 queryString 進行編碼。
| 瀏覽器 | Path 編碼 | QueryString 編碼 |
|---|---|---|
| Firefox | UTF-8 (E6 88 91 E6 98 AF) | UTF-8 (E6 88 91 E6 98 AF) |
| Chrome | UTF-8 (E6 88 91 E6 98 AF) | UTF-8 (E6 88 91 E6 98 AF) |
| IE | UTF-8 (E6 88 91 E6 98 AF) | GBK (CE D2 CA C7) |
編碼規範:非 ASCII 字符按編碼轉為 16 進制字節,每字節前加「%」。
在 org.apache.catalina.connector.CoyoteAdapter.convertURI 中,讀取 Connector 配置的 URIEncoding:
<Connector URIEncoding="utf-8" />
未配置則默認 ISO-8859-1。
首次調用 request.getParameter 時觸發 parseParameters,解碼邏輯:
request.setCharacterEncoding(enc),則用該編碼;Content-Type 中的 charset;若需讓 QueryString 也用 Body 編碼,需配置:
<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true"/>
數據拼接在 URL 後,屬於 QueryString 部分,受 URIEncoding 控制。若頁面 UTF-8 而 Tomcat 未配或配錯,會亂碼。常用修正:
new String(request.getParameter("name").getBytes("ISO-8859-1"), "UTF-8")
瀏覽器按 Content-Type charset 編碼,服務器同樣用該 charset 解碼,通常不會亂碼。可通過 request.setCharacterEncoding(charset) 手動指定。
escape():ISO Latin 編碼,輸出 %uXXXX 格式,不編碼「+」,不適合直接用於 URL。encodeURI():UTF-8 編碼整個 URL,不編碼特殊符號 ! @ # $ & * ( ) = : / ; ? + '。encodeURIComponent():UTF-8 編碼 URL 組成部分,比 encodeURI 更強,會編碼 ; / ? : @ & = + $ , # 等。推薦使用 encodeURIComponent 對參數單獨編碼。
// 前端
var url = '/ShowMoblieQRCode.servlet?name=我是cm';
window.location.href = encodeURI(url);
// 後台
String name = request.getParameter("name");
name = new String(name.getBytes("ISO-8859-1"), "UTF-8");
// 前端
window.location.href = encodeURI(encodeURI(url));
// 後台
String name = request.getParameter("name");
name = URLDecoder.decode(name, "UTF-8");
public class CharacterEncoding implements Filter {
private String encoding;
public void init(FilterConfig config) {
encoding = config.getInitParameter("encoding");
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
req.setCharacterEncoding(encoding);
chain.doFilter(req, resp);
}
}
// web.xml 配置 encoding=utf-8,url-pattern=/*
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String method = request.getMethod();
if ("post".equalsIgnoreCase(method)) {
request.setCharacterEncoding("UTF-8");
} else { // GET
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String name = paramNames.nextElement();
String[] values = request.getParameterValues(name);
if (values != null) {
for (int i = 0; i < values.length; i++)
values[i] = new String(values[i].getBytes("ISO-8859-1"), "UTF-8");
request.setAttribute(name, values);
}
}
}
chain.doFilter(request, response);
}
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>server.xml:<Connector URIEncoding="utf-8" />中文 URL 亂碼源於瀏覽器、操作系統、頁面編碼、服務器配置的多重不一致。最佳實踐:統一全鏈路 UTF-8,配置 Tomcat URIEncoding,配合 Filter 統一處理 GET/POST,前端採用 encodeURIComponent。徹底消除亂碼隱患。