中文亂碼是 Java Web 開發「必經之痛」,本質是 **編碼不一致** 導致的字節序列錯誤解碼。本文提供 **全鏈路修復指南**,覆蓋 Tomcat 連接器、前端代理、URL 參數、JSP 頁面、網絡傳輸層五大場景,附帶驗證清單與排查流程圖,助你一次性徹底解決亂碼問題。
字符串 --(編碼 Charset A)--> 字節序列 --(解碼 Charset B)--> 字符串
若 A != B → 亂碼
Java 內部:UTF-16 (char)
網絡傳輸:ISO-8859-1 (舊規範) / UTF-8 (現代標準)
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8" /> <!-- 關鍵:強制 URI 解碼為 UTF-8 -->
<Connector port="8009" protocol="AJP/1.3"
redirectPort="8443"
URIEncoding="UTF-8" /> <!-- 必須同步設置 -->
// 單個參數值編碼
const encodedValue = encodeURIComponent(value); // RFC 3986,空格→%20,不編碼 - _ . ~
// 整個 URL 查詢串構建
const params = new URLSearchParams();
params.append('title', '中文標題');
params.append('author', '張三');
const url = `/api/articles?${params.toString()}`; // 瀏覽器自動處理
// 通用:Spring MVC / Servlet 3.0+ 容器自動按 URIEncoding 解碼 GET 參數
// 若無 Spring,手動解碼:
String decoded = java.net.URLDecoder.decode(request.getParameter("title"), StandardCharsets.UTF_8.name());
// POST 表單/JSON 體:必須在讀取參數前設置
request.setCharacterEncoding("UTF-8"); // 僅影響 request.getParameter()、request.getReader()
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
String fixed = new String(broken.getBytes("ISO-8859-1"), "UTF-8");
原理:錯誤按 ISO-8859-1 解碼產生的字符串,其內部字節實為 UTF-8 字節,重新按 ISO-8859-1 編碼取回原字節,再按 UTF-8 正確解碼。
| 場景 | 發送端編碼 | 接收端解碼 | 代碼模板 |
|---|---|---|---|
| HTTP 請求發送 | UTF-8 | ISO-8859-1 (Servlet 規範默認) | `new String(str.getBytes("UTF-8"), "ISO-8859-1")` |
| HTTP 響應接收 | ISO-8859-1 | UTF-8 | `new String(str.getBytes("ISO-8859-1"), "UTF-8")` |
現代框架(Spring MVC、Jakarta EE 8+)已內部處理,業務代碼**無需手動轉碼**,只需確保 Tomcat `URIEncoding=UTF-8` 及請求/響應 `Content-Type` 正確。
-- MySQL (JDBC URL)
jdbc:mysql://localhost:3306/db?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
-- PostgreSQL
jdbc:postgresql://localhost:5432/db?charSet=UTF-8
-- 連接池
spring.datasource.hikari.connectionInitSql=SET NAMES utf8mb4
發現亂碼
│
├─ 請求參數亂碼?
│ ├─ GET → 檢查 Tomcat URIEncoding、前端 encodeURIComponent、雙重解碼
│ └─ POST → 檢查 request.setCharacterEncoding、CharacterEncodingFilter
│
├─ 響應頁面亂碼?
│ ├─ JSP → 檢查 pageEncoding、contentType、meta charset
│ ├─ 靜態資源 → 檢查 Nginx/Apache charset、Tomcat 默認 Servlet
│ └─ AJAX/JSON → 檢查 @ResponseBody/ResponseEntity charset、產出 Content-Type
│
├─ 數據庫存取亂碼?
│ └─ 檢查 JDBC characterEncoding、數據庫/表/列 utf8mb4、連接池 initSql
│
└─ 文件上傳/下載亂碼?
└─ 檢查 MultipartResolver 編碼、Content-Disposition filename 編碼 (RFC 5987)
# application.yml
server:
servlet:
encoding:
charset: UTF-8
force: true
enabled: true # 自動註冊 CharacterEncodingFilter
spring:
http:
encoding:
charset: UTF-8
force: true
datasource:
url: jdbc:mysql://localhost:3306/db?characterEncoding=utf8&useSSL=false
hikari:
connectionInitSql: SET NAMES utf8mb4
中文亂碼無銀彈,只有 **全鏈路統一 UTF-8** 才是正解。按本文清單逐項落地,配合自動化測試驗證,即可從根源消除亂碼,讓團隊專注業務創新。