原因:
1、Controller层上传文件导入
@PostMapping("/importAccount")
public ResultInfo importAccount(@RequestParam("file") MultipartFile file,
@RequestParam String code,
@RequestParam String type) throws IOException {
accountManagerService.importAccount(file, code, type);
return ResultInfo.success();
}
2、Service层调用feign接口
@Override
public void importAccount(MultipartFile file, String code, String type) {
//...此处省略其他业务逻辑...
/**
* 远程feign调用
*/
NetworkFeign networkFeign = (NetworkFeign)StaticApplication.getBean("networkFeign");
dto = networkFeign.loadNetworkDTOByBankCode(bankCode);
}
3、FeignClient定义
@FeignClient(name= "${application.name}",path = "/user/api/network", qualifiers = {"networkFeign"})
public interface NetworkFeign {
@PostMapping(value = "/loadNetworkDTOByBankCode")
NetworkDTO loadNetworkDTOByBankCode(@RequestParam("code") String code);
}
4、FeignProvider定义
@Slf4j
@RequestMapping(value = "/user/api/network")
@RestController
public class NetworkAPI {
@PostMapping(value = "/loadNetworkDTOByBankCode")
NetworkDTO loadNetworkDTOByBankCode(@RequestParam("code") String code) {
return networkOperateService.queryNetWorkByBankCode(code);
}
}
5、调用报错
Client端报错日志:
feign.FeignException$InternalServerError: [500 Internal Server Error] during [POST] to [http://user/user/api/network/loadNetworkDTOByBankCode?bank_code=002] [NetworkFeign#loadNetworkDTOByBankCode(String)]:
│ at feign.FeignException.serverErrorStatus(FeignException.java:250)
│ at feign.FeignException.errorStatus(FeignException.java:197)
│ at feign.FeignException.errorStatus(FeignException.java:185)
│ at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92)
│ at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96)
│ at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138)
│ at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
│ at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
│ at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory$1.proceed(FeignCachingInvocationHandlerFactory.java:66)
│ at org.springframework.cache.interceptor.CacheInterceptor.lambda$invoke$0(CacheInterceptor.java:54)
│ at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:351)
│ at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:64)
│ at org.springframework.cloud.openfeign.FeignCachingInvocationHandlerFactory.lambda$create$1(FeignCachingInvocationHandlerFactory.java:53)
at com.sun.proxy.$Proxy182.loadNetworkDTOByBankCode(Unknown Source)
│ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
│ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
│ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
│ at java.lang.reflect.Method.invoke(Method.java:498)
│ at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
│ at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
│ at com.sun.proxy.$Proxy183.loadNetworkDTOByBankCode(Unknown Source)
Server端报错日志:
java.lang.RuntimeException: java.io.IOException: UT000036: Connection terminated parsing multipart data
│ at io.undertow.servlet.spec.HttpServletRequestImpl.parseFormData(HttpServletRequestImpl.java:863)
│ at io.undertow.servlet.spec.HttpServletRequestImpl.getParameter(HttpServletRequestImpl.java:734)
│ at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:85)
│ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
│ at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
│ at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
│ at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
│ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
│ at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
│ at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
│ at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
│ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
│ at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
│ at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
│ at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
│ at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
│ at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
│ at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
│ at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
│ at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
│ at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
│ at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
│ at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
│ at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
│ at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
│ at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
│ at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
│ at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
│ at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
│ at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:275)
│ at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79)
│ at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134)
│ at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
│ at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
│ at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:255)
│ at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79)
│ at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100)
│ at io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
│ at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
│ at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
│ at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
│ at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
│ at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449)
│ at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
│ at java.lang.Thread.run(Thread.java:750)
│ Caused by: java.io.IOException: UT000036: Connection terminated parsing multipart data
│ at io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler.parseBlocking(MultiPartParserDefinition.java:231)
│ at io.undertow.servlet.spec.HttpServletRequestImpl.parseFormData(HttpServletRequestImpl.java:857)
│ ... 46 common frames omitted
分析:
因为从client端调用的request和feign调用是同一个请求,请求头也是同一个。而且从service端调用feign的时候,并没有传file给provider,所以导致请求头丢失。
有两种解决办法:
方式一:在拦截器里改请求头,把content-type的头带过去;
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
// 对于自动任务,起服务就调用参数的,没有请求信息,不需要传递
if (attributes == null) {
return;
}
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
// 跳过content-length,不然可能会报too many bites written问题
if ("content-length".equalsIgnoreCase(name) || "cookie".equalsIgnoreCase(name)) {
continue;
}
// 此处:把content-type的头带过去
if ("content-type".equalsIgnoreCase(name)) {
continue;
}
requestTemplate.header(name, values);
}
}
}
}
方式二:改request:不用feign调用,用普通的http调用;
@Override
public void importAccount(MultipartFile file, String code, String type) {
//...此处省略其他业务逻辑...
/**
* 远程feign调用
*/
// NetworkFeign networkFeign = (NetworkFeign)StaticApplication.getBean("networkFeign");
// dto = networkFeign.loadNetworkDTOByBankCode(bankCode);
// 此处不用feign调用,改用http调用,这里用hutool的工具类
String response = HttpRequest.post("http://user/user/api/network/loadNetworkDTOByBankCode?code=" + code).execute().body();
// 用http调用
log.info("'=====response======{}",response);
dto = JSONUtil.toBean(response, NetworkDTO.class);
}