最近项目转型使用SpringCloud框架下的微服务架构,各微服务之间使用Feign进行调用。期间,发现若被调用方法涉及到文件上传且仅存在单个文件时,一切正常,代码片段如下:

  1. @RequestMapping(value = "/if/****/add", method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  2. JSONObject add(@RequestPart(value = "file") MultipartFile file);

但若同时需要传递其他form-data数据时,则一直报错。

  1. @RequestMapping(value = "/if/****", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  2. Object add(@RequestParam(name = "objectCode") String objectCode, @RequestPart(name = "file") MultipartFile file);

报错信息为:

  1. org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
  2. at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:193)
  3. at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:109)
  4. at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
  5. at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)
  6. at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
  7. at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
  8. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
  9. at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
  10. at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
  11. at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
  12. at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
  13. at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
  14. at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
  15. at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
  16. at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
  17. at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
  18. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
  19. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  20. at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
  21. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  22. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  23. at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
  24. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  25. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  26. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

此时,feign日志为:

  1. 2018-12-22 03:42:37.591 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] ---> POST http://assembly-uiif/if/test1/public/t1?objectCode=test%3ASat+Dec+22+03%3A42%3A31+CST+2018 HTTP/1.1
  2. 2018-12-22 03:42:37.593 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] Content-Type: multipart/form-data; charset=UTF-8; boundary=167d24a8200
  3. 2018-12-22 03:42:37.594 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] Content-Length: 161
  4. 2018-12-22 03:42:37.595 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1]
  5. 2018-12-22 03:42:37.596 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] Binary data
  6. 2018-12-22 03:42:37.599 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] ---> END HTTP (161-byte body)
  7. 2018-12-22 03:42:37.618 INFO 66057 --- [io-31023-exec-2] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@65669249: startup date [Sat Dec 22 03:42:37 CST 2018]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@47df5041
  8. 2018-12-22 03:42:37.777 INFO 66057 --- [io-31023-exec-2] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
  9. 2018-12-22 03:42:38.615 INFO 66057 --- [io-31023-exec-2] c.netflix.config.ChainedDynamicProperty : Flipping property: assembly-uiif.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
  10. 2018-12-22 03:42:38.677 INFO 66057 --- [io-31023-exec-2] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-assembly-uiif
  11. 2018-12-22 03:42:38.786 INFO 66057 --- [io-31023-exec-2] c.netflix.loadbalancer.BaseLoadBalancer : Client: assembly-uiif instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=assembly-uiif,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
  12. 2018-12-22 03:42:38.796 INFO 66057 --- [io-31023-exec-2] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
  13. 2018-12-22 03:42:38.860 INFO 66057 --- [io-31023-exec-2] c.netflix.config.ChainedDynamicProperty : Flipping property: assembly-uiif.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
  14. 2018-12-22 03:42:38.863 INFO 66057 --- [io-31023-exec-2] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client assembly-epsic-uiif initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=assembly-uiif,current list of Servers=[192.168.43.31:20008],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
  15. },Server stats: [[Server:192.168.43.31:20008; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
  16. ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@114d8fc3
  17. 2018-12-22 03:42:39.606 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] <--- HTTP/1.1 200 (2006ms)
  18. 2018-12-22 03:42:39.607 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] cache-control: no-cache, no-store, max-age=0, must-revalidate
  19. 2018-12-22 03:42:39.608 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] content-type: application/json;charset=UTF-8
  20. 2018-12-22 03:42:39.608 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] date: Fri, 21 Dec 2018 19:42:39 GMT
  21. 2018-12-22 03:42:39.609 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] expires: 0
  22. 2018-12-22 03:42:39.610 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] pragma: no-cache
  23. 2018-12-22 03:42:39.610 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] transfer-encoding: chunked
  24. 2018-12-22 03:42:39.610 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] x-application-context: assembly-uiif:develop:20008
  25. 2018-12-22 03:42:39.610 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] x-content-type-options: nosniff
  26. 2018-12-22 03:42:39.613 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] x-frame-options: SAMEORIGIN
  27. 2018-12-22 03:42:39.613 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] x-xss-protection: 1; mode=block
  28. 2018-12-22 03:42:39.613 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1]
  29. 2018-12-22 03:42:39.615 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] {"head":{"orgId":0,"orgCode":"","vers":null,"reqId":null,"errorCode":1,"errorCodeI18n":"i18n.errorCode.1","errorMessage":"Required request part 'file' is not present","errorStack":"org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present\n\tat org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:193)\n\tat org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:109)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:661)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:742)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat com.egoonet.devtools.springstarter.iam.sso.config.web.MyFilterSecurityInterceptor.invoke(MyFilterSecurityInterceptor.java:61)\n\tat com.egoonet.devtools.springstarter.iam.sso.config.web.MyFilterSecurityInterceptor.doFilter(MyFilterSecurityInterceptor.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat com.***.web.MyFilterSecurityInterceptor.invoke(MyFilterSecurityInterceptor.java:61)\n\tat com.***.web.MyFilterSecurityInterceptor.doFilter(MyFilterSecurityInterceptor.java:31)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tat org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)\n\tat org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)\n\tat org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)\n\tat org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.lang.Thread.run(Thread.java:748)\n","userId":0,"appId":108},"info":{"now":"Sat Dec 22 03:42:39 CST 2018"}}
  30. 2018-12-22 03:42:39.615 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1] <--- END HTTP (12082-byte body)

很显然,feign发送的报文不对,正常的报文应该是:

  1. POST /if/test1/public/t1 HTTP/1.1
  2. Host: localhost:20008
  3. cache-control: no-cache
  4. Postman-Token: 1c879cba-fdf3-4b9a-b1ef-e3d5af7be37e
  5. Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
  6.  
  7. Content-Disposition: form-data; name="objectCode"
  8.  
  9. abcd
  10.  
  11. Content-Disposition: form-data; name="file"; filename="/Users/***/Downloads/03.jpg
  12.  
  13. ------WebKitFormBoundary7MA4YWxkTrZu0gW--

ok,到此可知,问题出在feign发送报文时发送错误。

查阅feign源码,参考网络资料,实现一个自定义注解:

  1. /**
  2. * Feign代理方法上,与 RequestPart 一起组成多参数模式的注解
  3. */
  4. @Target(ElementType.PARAMETER)
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Documented
  7. public @interface RequestPartParam {
  8.  
  9. String name() default "";
  10.  
  11. boolean required() default true;
  12.  
  13. }

实现自定义注解处理器:

  1. import feign.MethodMetadata;
  2. import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
  3.  
  4. import java.lang.annotation.Annotation;
  5. import java.lang.reflect.Method;
  6. import java.util.Map;
  7.  
  8. import static feign.Util.checkState;
  9. import static feign.Util.emptyToNull;
  10.  
  11. /**
  12. *
  13. */
  14. public class RequestPartParamParameterProcessor implements AnnotatedParameterProcessor {
  15.  
  16. private static final Class<RequestPartParam> ANNOTATION = RequestPartParam.class;
  17.  
  18. @Override
  19. public Class<? extends Annotation> getAnnotationType() {
  20. return ANNOTATION;
  21. }
  22.  
  23. @Override
  24. public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
  25. int parameterIndex = context.getParameterIndex();
  26. Class<?> parameterType = method.getParameterTypes()[parameterIndex];
  27. MethodMetadata data = context.getMethodMetadata();
  28.  
  29. if (Map.class.isAssignableFrom(parameterType)) {
  30. checkState(data.queryMapIndex() == null, "Query map can only be present once.");
  31. data.queryMapIndex(parameterIndex);
  32.  
  33. return true;
  34. }
  35.  
  36. RequestPartParam requestPartParam = ANNOTATION.cast(annotation);
  37. String name = requestPartParam.name();
  38. checkState(emptyToNull(name) != null,
  39. "RequestPartParam.name() was empty on parameter %s",
  40. parameterIndex);
  41. context.setParameterName(name);
  42.  
  43. data.formParams().add(name);
  44.  
  45. return true;
  46. }
  47.  
  48. }

实现自定义的编码器:

  1. import feign.RequestTemplate;
  2. import feign.codec.EncodeException;
  3. import feign.codec.Encoder;
  4. import feign.form.FormEncoder;
  5. import feign.form.MultipartFormContentProcessor;
  6. import feign.form.spring.SpringManyMultipartFilesWriter;
  7. import feign.form.spring.SpringSingleMultipartFileWriter;
  8. import lombok.val;
  9. import org.springframework.web.multipart.MultipartFile;
  10.  
  11. import java.lang.reflect.ParameterizedType;
  12. import java.lang.reflect.Type;
  13. import java.util.HashSet;
  14. import java.util.Map;
  15. import java.util.Set;
  16.  
  17. import static feign.form.ContentType.MULTIPART;
  18. import static java.util.Collections.singletonMap;
  19.  
  20. /**
  21. *
  22. */
  23. public class FeignSpringFormEncoder extends FormEncoder {
  24.  
  25. public FeignSpringFormEncoder () {
  26. this(new Encoder.Default());
  27. }
  28.  
  29. public FeignSpringFormEncoder (Encoder delegate) {
  30. super(delegate);
  31.  
  32. val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
  33. processor.addWriter(new SpringSingleMultipartFileWriter());
  34. processor.addWriter(new SpringManyMultipartFilesWriter());
  35. }
  36.  
  37. @Override
  38. public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
  39. if ((bodyType instanceof ParameterizedType) && ((ParameterizedType) bodyType).getRawType().equals(Map.class)) {
  40. val data = (Map<String, Object>) object;
  41. Set<String> nullSet = new HashSet<>();
  42. for (Map.Entry<String, Object> entry : data.entrySet()) {
  43. if (entry.getValue() == null) {
  44. nullSet.add(entry.getKey());
  45. }
  46. }
  47. for (String s : nullSet) {
  48. data.remove(s);
  49. }
  50. super.encode(data, MAP_STRING_WILDCARD, template);
  51. return;
  52. } else if (bodyType.equals(MultipartFile.class)) {
  53. val file = (MultipartFile) object;
  54. val data = singletonMap(file.getName(), object);
  55. super.encode(data, MAP_STRING_WILDCARD, template);
  56. return;
  57. } else if (bodyType.equals(MultipartFile[].class)) {
  58. val file = (MultipartFile[]) object;
  59. if (file != null) {
  60. val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
  61. super.encode(data, MAP_STRING_WILDCARD, template);
  62. return;
  63. }
  64. }
  65. super.encode(object, bodyType, template);
  66. }
  67.  
  68. }

定义bean:

  1. @Bean
  2. public RequestPartParamParameterProcessor requestPartParamParameterProcessor() {
  3. return new RequestPartParamParameterProcessor();
  4. }
  5.  
  6. @Bean
  7. public PathVariableParameterProcessor pathVariableParameterProcessor() {
  8. return new PathVariableParameterProcessor();
  9. }
  10.  
  11. @Bean
  12. public RequestParamParameterProcessor requestParamParameterProcessor() {
  13. return new RequestParamParameterProcessor();
  14. }
  15.  
  16. @Bean
  17. public RequestHeaderParameterProcessor requestHeaderParameterProcessor() {
  18. return new RequestHeaderParameterProcessor();
  19. }

注意,参阅  org.springframework.cloud.netflix.feign.support.SpringMvcContract 中的代码可知,使用自定义注解处理器时,必须自行处理另外3个系统默认注解处理器。

至此,重新编译,运行,工作正常。问题解决。

SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法的更多相关文章

  1. SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法(2)

    书接上文. 上文中描述了如何在 SpringCloud+Feign环境下上传文件与form-data同时存在的解决办法,实践证明基本可行,但却会引入其他问题. 主要导致的后果是: 1. 无法与普通Fe ...

  2. 不同环境下文件上传Uncaught SyntaxError: Unexpected end of input

    很奇怪的问题,相同的代码和相同的数据,在两台linux服务器上执行文件上传,一台正常上传,一台在ftl页面 报:Uncaught SyntaxError: Unexpected end of inpu ...

  3. ie下文件上传无权访问的问题

    最近项目遇到个问题,ie下文件上传无权访问,在网上找了很久才找到答案,原来是因为ie下不能用js触发input=file的点击事件,必须手动点击才可以.

  4. [原创]Struts2奇葩环境任意文件上传工具(解决菜刀无法传文件或上传乱码等问题)

    上面这问题问得好  1 不知道大家有没碰到有些Strus2站点  上传JSP后访问404 或者503    注意我说的是404或503不是403(要是403换个css/img等目录或许可以)    但 ...

  5. Web下文件上传下载的路径问题

    工程结构

  6. linux 下文件上传的两种工具(XFTP5和Putty之pscp)方式

    一.使用XFTP(,需要先在LINUX上安装启用FTP服务) 然后,在WINDOWS上启动XFPT6客户端,将下载的文件上传至LINUX 指定目录: 二.使用PUTTY软件安装目录下的PSCP命令 1 ...

  7. asp.net mvc下文件上传

    典型的文件上传表单 <form action="/File" enctype="multipart/form-data" method="pos ...

  8. SpringBoot下文件上传与下载的实现

    原文:http://blog.csdn.net/colton_null/article/details/76696674 SpringBoot后台如何实现文件上传下载? 最近做的一个项目涉及到文件上传 ...

  9. IE下文件上传, SCRIPT5: 拒绝访问 问题

    最近遇到一个比较奇葩的问题,某些ie浏览器在页面中上传文件时,无法上传.查看控制台报错: SCRIPT5: 拒绝访问. jquery-3.2.1.min.js, 行4 字符5725 .并且我的最新版I ...

随机推荐

  1. WIN10下Prolific USB-to-Serial Comm Port驱动

    最近在安装Prlific的时候,通过电脑自动安装启动后,发现系统无法识别,如下图所示: 还以为是驱动比较老,没有及时更新导致的,去官网下载最新的驱动,发现了这个列表: 这个驱动不支持win10. 后来 ...

  2. I2C和I2S的区别和使用方法

    I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.是微电子通信控制领域广泛采用的一种总线标准.它是同步通信的一种特 ...

  3. Testing - 软件测试知识梳理 - 测试阶段

    估算 测试对软件工作量的估算的准确性 测试评估软件系统的状况的准确性 关注点: 不准确的估算 不适当的开发过程 不真实的状态报告 如何知道对工作量的估算是正确的 估算工作量的工具很容易出错 对软件工作 ...

  4. php省市联动实现

    设计模式:ajax实现,数据库格式:id,name,parent_id 数据库: CREATE TABLE IF NOT EXISTS `city` ( `id` ) NOT NULL AUTO_IN ...

  5. Split()[1]中的[1]是什么意思

    split()方法是将指定字符串按某指定的分隔符进行拆分,拆分将会形成一个字符串的数组并返回 如:string str = "aa.bb.cc.dd"; string[] strA ...

  6. Python爬取网易云歌单

    目录 1. 关键点 2. 效果图 3. 源代码 1. 关键点 使用单线程爬取,未登录,爬取网易云歌单主要有三个关键点: url为https://music.163.com/discover/playl ...

  7. WC2017游记 & 能力残废康复计划

    懒癌晚期的蒟蒻一年多没有更Blog了… 这次冬眠营去绍一省好好地游玩了一番,体验了一段时间的豪华自助餐,成功吃胖… 第一课堂的东西基本还是没吸收…听着觉得有点道理,结果过几分钟就忘了…可能最大的收获就 ...

  8. Java并发编程笔记之Semaphore信号量源码分析

    JUC 中 Semaphore 的使用与原理分析,Semaphore 也是 Java 中的一个同步器,与 CountDownLatch 和 CycleBarrier 不同在于它内部的计数器是递增的,那 ...

  9. 基于xlua和mvvm的unity框架

    1.框架简介 这两天在Github上发现了xlua的作者车雄生前辈开源的一个框架—XUUI,于是下载下来学习了一下.XUUI基于xlua,又借鉴了mvvm的设计概念.xlua是目前很火的unity热更 ...

  10. 【学习笔记】JS经典异步操作,从闭包到async/await

    参考文献:王仕军——知乎专栏前端周刊 感谢作者的热心总结,本文在理解的基础上,根据自己能力水平作了一点小小的修改,在加深自己印象的同时也希望能和各位共同进步... 1. 异步与for循环 抛出一个问题 ...