陈同学
微服务
Accelerator
About
# Feign 上传文件的常见问题 Feign 作为 Spring Cloud 中 RPC 工具,利用注解来描述接口,简化了 Java HTTP Client 的调用过程,隐藏了实现细节。 本文将介绍利用 Feign 上传文件的几个常见问题。 * 如何上传一个/组文件 * 如何上传多种文件 * MultipartFile 参数不能为空问题 * 未提供 MultipartFile 参数接口报 no multipart boundary was found 问题 ## 如何上传一个/组文件 OpenFeign 默认不支持文件参数,但提供了 [feign-form](https://github.com/OpenFeign/feign-form) 拓展工具,这里简单拓展下官方Demo。 引入 **io.github.openfeign.form:feign-form:3.8.0** 和 **io.github.openfeign.form:feign-form-spring:3.8.0** maven依赖,注入 SpringFormEncoder ,在 `@FeignClient` 中配下configuration即可。 ```java @FeignClient(value = "cms-service", configuration = CmsService.MyConfig.class) public interface CmsService { // 也可以使用MultipartFile[]上传多个文件 @PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) void upload(@RequestPart("file") MultipartFile file); class MyConfig { @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(); } } } ``` 如果需要使用Spring标准的encoder,config变一下。 ```java class MyConfig { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Bean public Encoder feignFormEncoder () { return new SpringFormEncoder(new SpringEncoder(messageConverters)); } } ``` 需要特别注意 **feign-form** 和 **OpenFeign** 版本之间的关系,官方描述如下:  ## 如何上传多种文件 如下,假设有file1、file2两个文件,且不是数组。 ```java @FeignClient(value = "cms-service") public interface CmsService { @PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) void upload(@RequestPart("file1") MultipartFile file1, (@RequestPart("file2") MultipartFile file2); } ``` 在应用启动时处理CmsService时,就会直接报错: ``` java.lang.IllegalStateException: Method has too many Body parameters ``` Feign 不支持多个body参数。本身一次上传多个文件场景少见,改为每次传一个就好。 ## MultipartFile 参数不能为空 假设有MultipartFile类型参数,但 **required** 设置为 **false** 。 ```java @FeignClient(value = "cms-service") public interface CmsService { @PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) void upload(@RequestPart(value = "file", required = false) MultipartFile file); } ``` 会报错: ```java Caused by: java.lang.IllegalArgumentException: Body parameter 6 was null ``` 这个问题 [Body parameter was null problem when MultipartFile param is null](https://github.com/OpenFeign/feign/issues/933) 最近我在Github问过,解释是 Feign不支持这种特性,如果有需要,可以通过设置多个API解决,例子如下: ```java public interface MailClient { @PostMapping("/send", consumes = MediaType.APPLICATION_FORM_URL_ENCODED) void send(@RequestParam("message") String message); @PostMapping("/send", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) void send(@RequestParam("message") String message, @RequestPart("attachment") MultipartFile file); } ``` ## no multipart boundary was found 问题 上次一步的例子会引发新的问题,假设一个接口提供了两个参数。 ```java @RestController public class FileController { @PostMapping("/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) void upload(@RequestParam("message") String message, @RequestPart("attachment") MultipartFile file); } ``` 但使用时未提供MultipartFile类型参数。 ```java @FeignClient(value = "cms-service") public interface CmsService { @PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) void upload(@RequestParam("message") String message, ); } ``` 将会报如下错误: ``` org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found ``` 这是因为Feign只有存在MultipartFile类型参数时才会设置 **boundary**。在Feign的 MultipartFormContentProcessor 中,其中有一点就专门是用来添加boundary。 ```java public void process(...) throws EncodeException { String boundary = Long.toHexString(System.currentTimeMillis()); ... output.write("--").write(boundary).write("--").write("\r\n"); String contentTypeHeaderValue = this.getSupportedContentType().getHeader() + "; charset=" + charset.name() + "; boundary=" + boundary; template.header("Content-Type", new String[]{contentTypeHeaderValue}); } ``` 如果自己处理的话,可以在 RequestInterceptor 的实现类中模拟上面的方法,为 **multipart/form-data** 格式自定义一个boundary。 ## 小结 本文是一遍工具使用帖,小结一下,传文件注意几个点: * Feign 不支持多个body参数,body参数也不能为空 * 特别注意 feign-form 的版本 若对Feign源码感兴趣,可看看 [Spring Cloud 源码学习之 Feign](https://chenyongjun.vip/articles/94)。
本文由
cyj
创作,可自由转载、引用,但需署名作者且注明文章出处。
文章标题:
Feign 上传文件的常见问题
文章链接:
https://chenyongjun.vip/articles/109
扫码或搜索 cyjrun 关注微信公众号, 结伴学习, 一起努力