如何解決springboot引數傳中文亂碼
前言
本文案例來自業務部門的一個業務場景。他們的業務場景是他們部門研發了一個微服務上下文透傳元件,其透傳原理也挺簡單的,就是通過springboot攔截器把請求引數塞進threadlocal,然後下游通過threadlocal取到值,服務之間進行feign呼叫時,再把threadlocal的引數塞到header頭裡面。這個元件一直用得好好的,突然有一天因為傳的引數值是中文,導致亂碼。他們通過嘗試下面的各種方案,都無法解決。最後就讓我們部門排查處理。
業務部門的實現思路
他們一開始的思路方向是引數編碼不一致導致中文亂碼。於是他們就朝這個方向努力著,於是就有了如下方案
方案一:
String value = new String("我是中文亂碼".getBytes("ISO-8859-1"),"UTF-8");
這個是常用解決字串中文亂碼的方法之一
方案二:編寫字元編碼過濾器
@WebFilter(urlPatterns = "/*",filterName = "CharacterEncodingFilter") public class CharacterEncodingFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); filterChain.doFilter(request , response); } @Override public void destroy() { } }
然後啟動類上加上@ServletComponentScan。@WebFilter是servlet3.0才有的註解。當然這個過濾器你還可以這麼寫
public class CharacterEncodingFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); filterChain.doFilter(request , response); } @Override public void destroy() { } }
寫個bean配置類,如下
@Bean
public FilterRegistrationBean registerAuthFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new CharacterEncodingFilter();
registration.addUrlPatterns("/*");
registration.setName("CharacterEncodingFilter");
registration.setOrder(1);
return registration;
}
方案三:在application.yml指定編碼格式為utf-8
spring:
http:
encoding:
charset: utf-8
enabled: true
force: true
server:
tomcat:
uri-encoding: UTF-8
方案四:寫個StringHttpMessageConverter
百度來的基本上都是長這樣。不過在spring5版本WebMvcConfigurerAdapter這個類已經過時。其替代方式是實現WebMvcConfigurer介面或者繼承WebMvcConfigurationSupport。不過如果使用WebMvcConfigurationSupport,則會使springboot的mvc自動裝配失效。失效的原因是
拓展一點小知識,加上@EnableWebMvc同樣也會springboot的mvc自動裝配失效。其原因是
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration這個配置類繼承WebMvcConfigurationSupport
介紹那麼多種方案,並沒有解決按例的問題。那問題點出在哪裡?前邊案例我們提到過,在feign呼叫時,會把threadlocal的引數塞到header裡面。真正亂碼的問題點就在這裡,header是不支援中文傳輸的,如果你硬要傳輸,基本上接收方接到就是???這種看似亂碼的符號
破題關鍵
在把threadlocal的值塞到header裡面時,先做下URLEncoder編碼,形如
URLEncoder.encode(“我是中文亂碼”,"UTF-8")
在接收header引數時,做下URLDecoder.解碼,形如下
URLDecoder.decode(header中待解碼的引數值, "UTF-8")
總結
方向錯了,雖然再怎麼努力看似也啥沒卵用,不過至少可能會收穫其他意想不到的東西