Spring Cloud Zuul 中文檔案上傳亂碼
原文地址:https://segmentfault.com/a/1190000011650034
1 描述
使用Spring Cloud Zuul進行路由轉發時候嗎,檔案上傳會造成中文亂碼“?”。
1.1解決
Spring Cloud Zuul現在對於上傳檔案有兩種處理方式,一種是用spring mvc,另一種是zuulServlet。spring mvc對檔案處理不是很好,會導致亂碼問題,zuulServlet則不會。
網上比較常見的解決方案是在uri前加/zuul 使用zuul的servlet繞開springmvc來解決上傳檔案亂碼問題
如原文:https://my.oschina.net/kmnztech/blog/1618636
比如:原來你上傳檔案的路徑是/api/file/upload, 則你可以通過uri /zuul/api/file/upload來呼叫介面上傳檔案,中文編碼問題解決。
但是,在我專案中,在api路徑前加個zuul總覺得變扭,於是嘗試找到一種在改變最少就能解決問題的方法。
通過閱讀如官網 說明。
其實你可以通過zuul.servlet-path來配置使用zuul的servlet。接著,我在閘道器的application.properties中添加了:
zuul.servlet-path=/
1.2解決
對於已經固定了請求路徑的來說,再次修改路徑不是很好的,所以就採用如下方案:
在過濾器中,有一個pre的過濾器 ServletDetectionFilter,他的執行順序是-3,也是最先執行的過濾器,在這個過濾器中,有這麼一段程式碼:
public class ServletDetectionFilter extends ZuulFilter { public ServletDetectionFilter() { } public String filterType() { return "pre"; } public int filterOrder() { return -3; } public boolean shouldFilter() { return true; } public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); if (!(request instanceof HttpServletRequestWrapper) && this.isDispatcherServletRequest(request)) { ctx.set("isDispatcherServletRequest", true); } else { ctx.set("isDispatcherServletRequest", false); } return null; } private boolean isDispatcherServletRequest(HttpServletRequest request) { return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null; } }
在這個方法中,IS_DISPATCHER_SERVLET_REQUEST_KEY為false就會用ZuulServlet處理。如果沒加/zuul字首IS_DISPATCHER_SERVLET_REQUEST_KEY就會置為true,就會用spring mvc上傳。會出現亂碼問題。
那麼我們的一個解決方案是在在進入下一個過濾器之前我們就把我們的檔案上傳的請求用ZuulServlet處理,所以我們可以重寫這個方法,根據contentType判斷請求如果是multipart就將IS_DISPATCHER_SERVLET_REQUEST_KEY置為false,那麼它就會用ZuulServlet處理。
@Component public class ServletDetectionFilterFile extends ServletDetectionFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); if (!(request instanceof HttpServletRequestWrapper) && this.isDispatcherServletRequest(request) && !this.isMultipartContent(request)) { ctx.set("isDispatcherServletRequest", true); } else { ctx.set("isDispatcherServletRequest", false); } return null; } private boolean isDispatcherServletRequest(HttpServletRequest request) { return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null; } /** * 判斷是否是multipart/form-data請求 * @param request 請求 * @return 是否是 */ private boolean isMultipartContent(HttpServletRequest request) { String requesType = "post"; if(!requesType.equals(request.getMethod().toLowerCase())) { return false; } //獲取Content-Type String contentType = request.getContentType(); return (contentType != null) && (contentType.toLowerCase().startsWith("multipart/")); } }
到這裡還沒有結束,還有一個很坑的地方,在最後以前pre過濾器中,他會對url進行處理。如果該請求是ZuulServlet處理的,那麼他會把url的前面幾位用的zuulServletPath替代,zuulServletPath預設就是剛才我們替代的字首 /zuul。那麼如果你不處理的話,你的請求路徑將會變化。所以在這裡我們將這個預設的zuulServletPath改成空值,就不會替換啦。在配置檔案裡面加上:
zuul.servletPath:
後面的值不填。