SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法
最近项目转型使用SpringCloud框架下的微服务架构,各微服务之间使用Feign进行调用。期间,发现若被调用方法涉及到文件上传且仅存在单个文件时,一切正常,代码片段如下:
- @RequestMapping(value = "/if/****/add", method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- JSONObject add(@RequestPart(value = "file") MultipartFile file);
但若同时需要传递其他form-data数据时,则一直报错。
- @RequestMapping(value = "/if/****", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- Object add(@RequestParam(name = "objectCode") String objectCode, @RequestPart(name = "file") MultipartFile file);
报错信息为:
- org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
- at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:193)
- at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:109)
- at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
- at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)
- at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
- at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
- at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
- at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
- at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
- at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
- at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
- at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
- at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
- at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
- at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
- at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
- at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
- at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
- at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
此时,feign日志为:
- 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
- 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
- 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
- 2018-12-22 03:42:37.595 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1]
- 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
- 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)
- 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
- 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
- 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
- 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
- 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
- 2018-12-22 03:42:38.796 INFO 66057 --- [io-31023-exec-2] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
- 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
- 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;]
- },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]
- ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@114d8fc3
- 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)
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 2018-12-22 03:42:39.613 DEBUG 66057 --- [io-31023-exec-2] c.e.l.c.m.t.f.TestFileFeignController : [TestFileFeignController#t1]
- 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"}}
- 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发送的报文不对,正常的报文应该是:
- POST /if/test1/public/t1 HTTP/1.1
- Host: localhost:20008
- cache-control: no-cache
- Postman-Token: 1c879cba-fdf3-4b9a-b1ef-e3d5af7be37e
- Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
- Content-Disposition: form-data; name="objectCode"
- abcd
- Content-Disposition: form-data; name="file"; filename="/Users/***/Downloads/03.jpg
- ------WebKitFormBoundary7MA4YWxkTrZu0gW--
ok,到此可知,问题出在feign发送报文时发送错误。
查阅feign源码,参考网络资料,实现一个自定义注解:
- /**
- * Feign代理方法上,与 RequestPart 一起组成多参数模式的注解
- */
- @Target(ElementType.PARAMETER)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface RequestPartParam {
- String name() default "";
- boolean required() default true;
- }
实现自定义注解处理器:
- import feign.MethodMetadata;
- import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Method;
- import java.util.Map;
- import static feign.Util.checkState;
- import static feign.Util.emptyToNull;
- /**
- *
- */
- public class RequestPartParamParameterProcessor implements AnnotatedParameterProcessor {
- private static final Class<RequestPartParam> ANNOTATION = RequestPartParam.class;
- @Override
- public Class<? extends Annotation> getAnnotationType() {
- return ANNOTATION;
- }
- @Override
- public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
- int parameterIndex = context.getParameterIndex();
- Class<?> parameterType = method.getParameterTypes()[parameterIndex];
- MethodMetadata data = context.getMethodMetadata();
- if (Map.class.isAssignableFrom(parameterType)) {
- checkState(data.queryMapIndex() == null, "Query map can only be present once.");
- data.queryMapIndex(parameterIndex);
- return true;
- }
- RequestPartParam requestPartParam = ANNOTATION.cast(annotation);
- String name = requestPartParam.name();
- checkState(emptyToNull(name) != null,
- "RequestPartParam.name() was empty on parameter %s",
- parameterIndex);
- context.setParameterName(name);
- data.formParams().add(name);
- return true;
- }
- }
实现自定义的编码器:
- import feign.RequestTemplate;
- import feign.codec.EncodeException;
- import feign.codec.Encoder;
- import feign.form.FormEncoder;
- import feign.form.MultipartFormContentProcessor;
- import feign.form.spring.SpringManyMultipartFilesWriter;
- import feign.form.spring.SpringSingleMultipartFileWriter;
- import lombok.val;
- import org.springframework.web.multipart.MultipartFile;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- import static feign.form.ContentType.MULTIPART;
- import static java.util.Collections.singletonMap;
- /**
- *
- */
- public class FeignSpringFormEncoder extends FormEncoder {
- public FeignSpringFormEncoder () {
- this(new Encoder.Default());
- }
- public FeignSpringFormEncoder (Encoder delegate) {
- super(delegate);
- val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
- processor.addWriter(new SpringSingleMultipartFileWriter());
- processor.addWriter(new SpringManyMultipartFilesWriter());
- }
- @Override
- public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
- if ((bodyType instanceof ParameterizedType) && ((ParameterizedType) bodyType).getRawType().equals(Map.class)) {
- val data = (Map<String, Object>) object;
- Set<String> nullSet = new HashSet<>();
- for (Map.Entry<String, Object> entry : data.entrySet()) {
- if (entry.getValue() == null) {
- nullSet.add(entry.getKey());
- }
- }
- for (String s : nullSet) {
- data.remove(s);
- }
- super.encode(data, MAP_STRING_WILDCARD, template);
- return;
- } else if (bodyType.equals(MultipartFile.class)) {
- val file = (MultipartFile) object;
- val data = singletonMap(file.getName(), object);
- super.encode(data, MAP_STRING_WILDCARD, template);
- return;
- } else if (bodyType.equals(MultipartFile[].class)) {
- val file = (MultipartFile[]) object;
- if (file != null) {
- val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
- super.encode(data, MAP_STRING_WILDCARD, template);
- return;
- }
- }
- super.encode(object, bodyType, template);
- }
- }
定义bean:
- @Bean
- public RequestPartParamParameterProcessor requestPartParamParameterProcessor() {
- return new RequestPartParamParameterProcessor();
- }
- @Bean
- public PathVariableParameterProcessor pathVariableParameterProcessor() {
- return new PathVariableParameterProcessor();
- }
- @Bean
- public RequestParamParameterProcessor requestParamParameterProcessor() {
- return new RequestParamParameterProcessor();
- }
- @Bean
- public RequestHeaderParameterProcessor requestHeaderParameterProcessor() {
- return new RequestHeaderParameterProcessor();
- }
注意,参阅 org.springframework.cloud.netflix.feign.support.SpringMvcContract 中的代码可知,使用自定义注解处理器时,必须自行处理另外3个系统默认注解处理器。
至此,重新编译,运行,工作正常。问题解决。
SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法的更多相关文章
- SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法(2)
书接上文. 上文中描述了如何在 SpringCloud+Feign环境下上传文件与form-data同时存在的解决办法,实践证明基本可行,但却会引入其他问题. 主要导致的后果是: 1. 无法与普通Fe ...
- 不同环境下文件上传Uncaught SyntaxError: Unexpected end of input
很奇怪的问题,相同的代码和相同的数据,在两台linux服务器上执行文件上传,一台正常上传,一台在ftl页面 报:Uncaught SyntaxError: Unexpected end of inpu ...
- ie下文件上传无权访问的问题
最近项目遇到个问题,ie下文件上传无权访问,在网上找了很久才找到答案,原来是因为ie下不能用js触发input=file的点击事件,必须手动点击才可以.
- [原创]Struts2奇葩环境任意文件上传工具(解决菜刀无法传文件或上传乱码等问题)
上面这问题问得好 1 不知道大家有没碰到有些Strus2站点 上传JSP后访问404 或者503 注意我说的是404或503不是403(要是403换个css/img等目录或许可以) 但 ...
- Web下文件上传下载的路径问题
工程结构
- linux 下文件上传的两种工具(XFTP5和Putty之pscp)方式
一.使用XFTP(,需要先在LINUX上安装启用FTP服务) 然后,在WINDOWS上启动XFPT6客户端,将下载的文件上传至LINUX 指定目录: 二.使用PUTTY软件安装目录下的PSCP命令 1 ...
- asp.net mvc下文件上传
典型的文件上传表单 <form action="/File" enctype="multipart/form-data" method="pos ...
- SpringBoot下文件上传与下载的实现
原文:http://blog.csdn.net/colton_null/article/details/76696674 SpringBoot后台如何实现文件上传下载? 最近做的一个项目涉及到文件上传 ...
- IE下文件上传, SCRIPT5: 拒绝访问 问题
最近遇到一个比较奇葩的问题,某些ie浏览器在页面中上传文件时,无法上传.查看控制台报错: SCRIPT5: 拒绝访问. jquery-3.2.1.min.js, 行4 字符5725 .并且我的最新版I ...
随机推荐
- WIN10下Prolific USB-to-Serial Comm Port驱动
最近在安装Prlific的时候,通过电脑自动安装启动后,发现系统无法识别,如下图所示: 还以为是驱动比较老,没有及时更新导致的,去官网下载最新的驱动,发现了这个列表: 这个驱动不支持win10. 后来 ...
- I2C和I2S的区别和使用方法
I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.是微电子通信控制领域广泛采用的一种总线标准.它是同步通信的一种特 ...
- Testing - 软件测试知识梳理 - 测试阶段
估算 测试对软件工作量的估算的准确性 测试评估软件系统的状况的准确性 关注点: 不准确的估算 不适当的开发过程 不真实的状态报告 如何知道对工作量的估算是正确的 估算工作量的工具很容易出错 对软件工作 ...
- php省市联动实现
设计模式:ajax实现,数据库格式:id,name,parent_id 数据库: CREATE TABLE IF NOT EXISTS `city` ( `id` ) NOT NULL AUTO_IN ...
- Split()[1]中的[1]是什么意思
split()方法是将指定字符串按某指定的分隔符进行拆分,拆分将会形成一个字符串的数组并返回 如:string str = "aa.bb.cc.dd"; string[] strA ...
- Python爬取网易云歌单
目录 1. 关键点 2. 效果图 3. 源代码 1. 关键点 使用单线程爬取,未登录,爬取网易云歌单主要有三个关键点: url为https://music.163.com/discover/playl ...
- WC2017游记 & 能力残废康复计划
懒癌晚期的蒟蒻一年多没有更Blog了… 这次冬眠营去绍一省好好地游玩了一番,体验了一段时间的豪华自助餐,成功吃胖… 第一课堂的东西基本还是没吸收…听着觉得有点道理,结果过几分钟就忘了…可能最大的收获就 ...
- Java并发编程笔记之Semaphore信号量源码分析
JUC 中 Semaphore 的使用与原理分析,Semaphore 也是 Java 中的一个同步器,与 CountDownLatch 和 CycleBarrier 不同在于它内部的计数器是递增的,那 ...
- 基于xlua和mvvm的unity框架
1.框架简介 这两天在Github上发现了xlua的作者车雄生前辈开源的一个框架—XUUI,于是下载下来学习了一下.XUUI基于xlua,又借鉴了mvvm的设计概念.xlua是目前很火的unity热更 ...
- 【学习笔记】JS经典异步操作,从闭包到async/await
参考文献:王仕军——知乎专栏前端周刊 感谢作者的热心总结,本文在理解的基础上,根据自己能力水平作了一点小小的修改,在加深自己印象的同时也希望能和各位共同进步... 1. 异步与for循环 抛出一个问题 ...