You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
we were using Spring Cloud Zuul as our API Gateway, and had the requirement of uploading somewhat large files (100MB ~ <1GB). Since Zuul is now in maintenance mode, I wished to try and migrate towards Spring Cloud Gateway so that we can benefit from the better backbone on which it rests.
I've run into an issue with proxying a multipart file upload request through the Gateway to a backend service using Spring Cloud Finchley.SR2 and Spring Boot 2.0.6.RELEASE. I've created a repository that can replicate this issue here: https://github.com/filpano/multipart-issue-example.
I initially tried to use Greenwich and 2.1.3.RELEASE, respectively, but: 1) I had some issues with getting those versions to run locally, and 2) most of our services currently reside on Finchley/2.0.6.RELEASE, so I tried to reproduce the issue nearest to where I encountered it.
The Gateway seems to be able to stream the request without buffering as expected. However, the issue seems to be on the service side (controller repo). If spring.http.multipart.enabled is false, it does not seem able to get a multipart file out of the request (using the request itself). If it is left enabled (as is default), then an exception is generated (stacktrace is at the bottom of this post). There are two endpoints in the controller for both cases, though spring.http.multipart.enabled needs to be toggled to see both cases.
When the multipart file is uploaded directly to the service, it seems that everything is working as expected. Currently, the applications are set up so the Gateway dynamically registers the routes through Eureka, as this is our actual setup. This means that I did not verify this erroneous behaviour using statically configured routes, though I do not think (and hope) that it does not affect any forwarding behaviour.
I realize that Zuul/Gateway were never meant for large (GB+) uploads, but it is convenient to have a single exposed entrypoint around which to develop and our upload-size requirements are not steep at this time. If we end up requiring larger uploads, obviously we will need to directly expose those endpoints somehow, but I imagine that the Gateway should be able to handle medium-sized uploads (100-200MB) without any issues.
If you require more information, please let me know and I will try to provide it ASAP.
Stacktrace of exception occuring at Service level:
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:199) ~[spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:112) ~[spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) ~[spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) [spring-webmvc-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.34.jar:8.5.34]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.34.jar:8.5.34]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
The text was updated successfully, but these errors were encountered:
After some more extensive searching, it seems that the issue I have encountered is exactly the same one as spring-cloud/spring-cloud-netflix#2907, which was fixed in Greenwich.RELEASE/Spring Boot 2.1.1.
Since Spring Cloud Gateway also bases on Spring / Boot, this issue should also have been fixed in Greenwich.RELEASE / Spring Boot 2.1.x, so I'm closing this issue. If it seems to persist under the same conditions, I will reopen this issue. Thanks!
Hello,
we were using Spring Cloud Zuul as our API Gateway, and had the requirement of uploading somewhat large files (100MB ~ <1GB). Since Zuul is now in maintenance mode, I wished to try and migrate towards Spring Cloud Gateway so that we can benefit from the better backbone on which it rests.
I've run into an issue with proxying a multipart file upload request through the Gateway to a backend service using Spring Cloud Finchley.SR2 and Spring Boot 2.0.6.RELEASE. I've created a repository that can replicate this issue here: https://github.com/filpano/multipart-issue-example.
I initially tried to use Greenwich and 2.1.3.RELEASE, respectively, but: 1) I had some issues with getting those versions to run locally, and 2) most of our services currently reside on Finchley/2.0.6.RELEASE, so I tried to reproduce the issue nearest to where I encountered it.
The Gateway seems to be able to stream the request without buffering as expected. However, the issue seems to be on the service side (
controller
repo). Ifspring.http.multipart.enabled
is false, it does not seem able to get a multipart file out of the request (using the request itself). If it is left enabled (as is default), then an exception is generated (stacktrace is at the bottom of this post). There are two endpoints in the controller for both cases, thoughspring.http.multipart.enabled
needs to be toggled to see both cases.When the multipart file is uploaded directly to the service, it seems that everything is working as expected. Currently, the applications are set up so the Gateway dynamically registers the routes through Eureka, as this is our actual setup. This means that I did not verify this erroneous behaviour using statically configured routes, though I do not think (and hope) that it does not affect any forwarding behaviour.
I realize that Zuul/Gateway were never meant for large (GB+) uploads, but it is convenient to have a single exposed entrypoint around which to develop and our upload-size requirements are not steep at this time. If we end up requiring larger uploads, obviously we will need to directly expose those endpoints somehow, but I imagine that the Gateway should be able to handle medium-sized uploads (100-200MB) without any issues.
If you require more information, please let me know and I will try to provide it ASAP.
Stacktrace of exception occuring at Service level:
The text was updated successfully, but these errors were encountered: