首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Web 中文亂碼終極解決方案:請求響應編碼全鏈路統一

     編輯:Java 相關知識

亂碼根因:編碼與解碼不一致

計算機只識別 0/1。字符 → 位元組叫編碼,位元組 → 字符叫解碼。編碼集 ≠ 解碼集 即產生亂碼。Java Web 涉及四個關鍵環節:

瀏覽器 --(HTTP Request)--> Tomcat --(Servlet API)--> Java Code
    │                           │                    │
  編碼(UTF-8)               解碼(ISO-8859-1?)      處理
    │                           │                    │
    ◄--(HTTP Response)--- Tomcat --(Servlet API)-- 返回
        解碼(UTF-8?)            編碼(ISO-8859-1?)

環節一:頁面編碼聲明 (瀏覽器端)

<!-- HTML5 簡潔寫法,必須放在  首行 -->
<meta charset="UTF-8">

<!-- 表單提交強制指定編碼 (GET 方式無效) -->
<form action="/submit" method="post" accept-charset="UTF-8">

環節二:Tomcat 連接器配置 (服務器層)

<!-- server.xml  節點 -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="UTF-8" 
           useBodyEncodingForURI="true" />
  • URIEncoding="UTF-8":解決 GET 請求 URL 參數中文亂碼 (Tomcat 8+ 默認已是 UTF-8)
  • useBodyEncodingForURI="true":讓 POST 請求體編碼也受 request.setCharacterEncoding 影響

環節三:Servlet 請求編碼設置 (代碼層 - POST)

@WebServlet("/submit")
public class SubmitServlet extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 關鍵:必須在讀取任何參數前調用,且僅對 POST 有效
        req.setCharacterEncoding("UTF-8");
        
        String username = req.getParameter("username"); // 正確解碼
        // 業務邏輯...
    }
}

原理:POST 數據在 Request Body,Tomcat 默認用 ISO-8859-1 解碼。調用 setCharacterEncoding 會重新用指定字符集解析 Body。

環節四:GET 請求中文參數處理

GET 參數在 URL,setCharacterEncoding 無效。兩種方案:

  1. 手動轉碼 (不推薦,易漏):new String(req.getParameter("name").getBytes("ISO-8859-1"), "UTF-8")
  2. 全局 Filter 統一處理 (推薦,Spring 專案直接用 CharacterEncodingFilter):
    @WebFilter("/*")
    public class EncodingFilter implements Filter {
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
                throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
            
            // 1. 請求編碼 (POST 自動生效,GET 需手動處理 URL)
            request.setCharacterEncoding("UTF-8");
            
            // 2. GET 參數手動轉碼包裝
            if ("GET".equalsIgnoreCase(request.getMethod())) {
                request = new HttpServletRequestWrapper(request) {
                    @Override public String getParameter(String name) {
                        String val = super.getParameter(name);
                        if (val == null) return null;
                        try { return new String(val.getBytes("ISO-8859-1"), "UTF-8"); }
                        catch (UnsupportedEncodingException e) { return val; }
                    }
                    @Override public String[] getParameterValues(String name) {
                        String[] vals = super.getParameterValues(name);
                        if (vals == null) return null;
                        return Arrays.stream(vals)
                            .map(v -> {
                                try { return new String(v.getBytes("ISO-8859-1"), "UTF-8"); }
                                catch (UnsupportedEncodingException e) { return v; }
                            }).toArray(String[]::new);
                    }
                };
            }
            
            // 3. 響應編碼
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            
            chain.doFilter(request, response);
        }
    }
    

環節五:響應編碼設置 (輸出端)

// 方式一:雙重保險 (推薦)
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8"); // 告訴瀏覽器以 UTF-8 解碼

// 方式二:一行搞定 (等效)
resp.setContentType("text/html;charset=UTF-8"); // 內部會調用 setCharacterEncoding

// JSON 接口
resp.setContentType("application/json;charset=UTF-8");

Spring Boot 專項配置 (零代碼)

# application.yml
server:
  servlet:
    encoding:
      charset: UTF-8
      force: true          # 強制請求/響應編碼
      enabled: true
# 等同於自動註冊 CharacterEncodingFilter(forceEncoding=true)

避坑清單

現象原因修正
POST 中文亂碼未調用 request.setCharacterEncoding("UTF-8")Filter 或 Servlet 首行設置
GET 中文亂碼Tomcat 默認 ISO-8859-1 解碼 URLserver.xml URIEncoding="UTF-8" + Filter 包裝
響應頁面亂碼未設置 Content-Type charsetresp.setContentType("text/html;charset=UTF-8")
文件下載中文名亂碼Header 編碼不符合 RFC 5987URLEncoder.encode(name, "UTF-8").replace("+", "%20") + filename*=UTF-8''
數據庫存儲亂碼連接串無字符集 / 表字符集非 utf8mb4JDBC URL ?characterEncoding=utf8&useUnicode=true,表 CHARSET=utf8mb4

總結

中文亂碼本質是 編碼/解碼鏈路任意一環不一致。解決之道:全鏈路 UTF-8 —— 頁面 <meta charset="UTF-8">、Tomcat URIEncoding="UTF-8"、Filter 統一 setCharacterEncoding("UTF-8")、響應 setContentType(...;charset=UTF-8)、數據庫 utf8mb4。Spring Boot 僅需 server.servlet.encoding.force=true 一行配置。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved