Servlet 請求轉發(RequestDispatcher.forward())時出現亂碼,且單獨訪問目標頁面正常。本文揭示核心原因:首次調用 response.getWriter() 會鎖定響應字符編碼為 ISO-8859-1,後續 setCharacterEncoding 失效,並給出三種標準解決方案。
@WebServlet("/forward")
public class ForwardServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// ❌ 錯誤順序:先獲取 Writer,再設置編碼
PrintWriter out = resp.getWriter(); // 此處鎖定編碼為 ISO-8859-1
resp.setCharacterEncoding("UTF-8"); // 無效!
resp.setContentType("text/html;charset=utf-8"); // 無效!
RequestDispatcher rd = req.getRequestDispatcher("/target.jsp");
rd.forward(req, resp); // target.jsp 顯示亂碼
}
}
HttpServletResponseWrapper.getWriter() 內部調用:
public PrintWriter getWriter() throws IOException {
if (writer != null) return writer;
// 關鍵:若未顯式設置 charset,默認 ISO-8859-1
String charset = getCharacterEncoding();
if (charset == null) charset = "ISO-8859-1"; // Servlet 規範默認值
writer = new PrintWriter(new OutputStreamWriter(getOutputStream(), charset));
return writer;
}
getWriter() → 創建 OutputStreamWriter(..., "ISO-8859-1")PrintWriter 綁定該編碼器setCharacterEncoding("UTF-8") 僅修改響應頭 Content-Type,不會重新創建 Writerresponse 對象,Writer 已鎖定 → 輸出亂碼@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// ✅ 正確順序:先編碼,後 getWriter
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter(); // 此時綁定 UTF-8
RequestDispatcher rd = req.getRequestDispatcher("/target.jsp");
rd.forward(req, resp);
}
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
req.setCharacterEncoding("UTF-8"); // 兼容 POST 請求體
chain.doFilter(req, resp);
}
}
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
但轉發前的 Servlet 必須不調用 getWriter(),否則仍會鎖定編碼。
| 場景 | 原因 | 解決 |
|---|---|---|
| POST 請求體亂碼 | Tomcat 默認 ISO-8859-1 解碼 Body | req.setCharacterEncoding("UTF-8") 在 getParameter() 前調用 |
| GET 參數亂碼 | Tomcat 8+ 默認 UTF-8,舊版需配置 URIEncoding="UTF-8" | server.xml Connector 加 URIEncoding="UTF-8" |
| 轉發亂碼 | getWriter() 鎖定編碼 | 本文三種方案 |
EncodingFilter,覆蓋所有請求contentType + pageEncoding 同時聲明<Connector URIEncoding="UTF-8" /> 解決 GET 參數characterEncoding=utf8Servlet 轉發亂碼的核心是 response.getWriter() 過早調用鎖定了 ISO-8859-1 編碼。鐵律:**響應編碼設置必須在獲取輸出流之前完成**。生產環境請統一使用 Filter 方案,從架構層面消滅編碼問題。