# 問題
Spring 提供了CharcterEncodingFilter,專門解決字符串編碼的問題。
詭異的是,在類 AbstractAnnotationConfigDispatcherServletInitializer 方法 getFilters 設置了 CharcterEncodingFilter,結果字符集還是亂碼。
# 排查
首先檢查是否是上傳的值編碼錯誤:通過 Chrome Debug 工具,傳出的值經過解碼,是正確的。
再考慮是否是 request 解碼錯誤。request.getCharacterEncoding() 的返回值為 "utf-8"。解碼也是沒問題。
# 核心
契機:我有一天想從 Eclipse 轉入 IDEA,便把項目重新導入一遍。導入的過程中我會想起,一開始是沒有問題,后來加了一個模塊就開始有問題了。后來想想這個模塊是 Spring Security。
在 Servlet 中,Filter 是一個鏈,而 Spring Security 是第一個過濾鏈。字符編碼必須在第一個鏈過濾,因為解碼之后就不再解碼了(直解碼一次,之后就返回第一次解碼的內容)。
# 解決
在 Security 模塊注冊 CharcterEncodingFilter。
public class TeachingTestSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { @Override protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter()); characterEncodingFilter.setInitParameter("encoding", "UTF-8"); characterEncodingFilter.setInitParameter("forceEncoding", "true"); characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*"); } }