【Feign】⭐️使用 openFeign 时传递 MultipartFile 类型的参数参考
💥💥✈️✈️欢迎阅读本文章❤️❤️💥💥
🏆本篇文章阅读大约耗时三分钟。
⛳️motto:不积跬步、无以千里
📋📋📋本文目录如下:🎁🎁🎁
目录
前言
模拟
解决方案(一)
解决方案(二)
章末
前言
小伙伴们大家好,这篇文章主要描述下最近在开发时遇到的一个服务之间通过 openFeign 调用时遇到的参数传递问题,如题目所述,该参数类型正是 MultipartFile。
在网上有很多解决方案,比如另外引入 feign + spring 的联合依赖(叫什么记不住了),或者转换成字节数组传递,接收方再转换为 MultipartFile 对象(要引入MockMultifile 依赖,应该是这个),然后还有本文使用的这种方案(不用引入依赖,改动也不多)
先来模拟下大致的使用场景,也可以直接跳过模拟看解决方案(环境不同,也可能解决不了各位的问题,请谅解)
模拟
本地模拟就以两个简单服务之间的调用实现,对应一个客户端,一个服务端,场景就是从客户端调用服务端的接口,中间需要传递 MultipartFile 类型的参数,要怎么成功把参数传递到服务端
1、客户端会暴露一个接口,参数为 MultipartFile 类型的 file 参数,然后通过 feign 调用服务端的接口,feign 配置也很简单,指定了服务端地址和定义了一个方法
2、服务端
提供的方法很简单,打印 file 的大小,然后返回给客户端该参数的 大小+原始名称
3、测试
目前这种情况,在调用客户端暴露的接口,参数可以成功传到客户端,但是从客户端传到服务端的时候会遇到异常,服务端提示异常如下:
Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause
解决方案(一)
(补充:该方法只适用于整个服务使用的 feign 传递参数时不会有 @RequestBody 类型的传递方式,有这种请求和 Multipartfile 类型请求的,可以再往下看)
指定自定义编码器,并且标注请求头,使用 @RequestPart 注解标注参数。具体实现案例如下:
1、编码配置类
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author HuangBenben */
@Configuration
public class FeignConfig {@Beanpublic Encoder devEncoder() {return new SpringFormEncoder(); // 使用 SpringFormEncoder 实现 Encoder 接口}
}
2、feign 接口指定编码和请求头以及参数注解
@FeignClient 注解中指定 configuration 的值为 自己创建的编码配置类
具体的方法定义加上对应请求头
使用 @RequestPart 注解
3.服务端调整
服务端在接收参数时也使用 @RequestPart 注解
4、测试
可以正常传递参数并且接收到了服务端的返回值
解决方案(二)
首先很抱歉上面的解决方案没有调研仔细,会影响到下面这种情况
昨儿查了许久找到的简单实现 MultipartFile 类型通过 feign 在服务间传递的方法,今儿发现有别的隐患,如果服务间也有 @Requestbody 类型的参数传递,在上面的解决方法基础上会报错,参数传递失败,场景模拟和解决方案如下:
1、如下使用会有异常,当前服务有别的 feing 定义,并且使用 @RequestBody 注解,调用时客户端直接异常:
feign.codec.EncodeException: class org.example.entity.Email is not a type supported by this encoder.
假设要传递这种请求体
2、解决
在原先自定义的 FeignConfig 基础上调整为以下代码,再次测试 @RequestBody , MultipartFile 类型 以及 @RequestParam 传递都没问题
这样配置的话,前面的那种解决方法中要在 feign 中声明指定配置类的操作也不需要了
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author HuangBenben*/
@Configuration
public class FeignConfig {@Beanpublic Encoder feignEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {// 将 Spring 的 HttpMessageConverters 适配为 Feign 的 EncoderEncoder springEncoder = new SpringEncoder(messageConverters);// 包装成支持表单编码的 Encoderreturn new SpringFormEncoder(springEncoder);}
}
这种调整是因为 feign 的自动调整传递形式,详细解释如下:
通过配置 SpringFormEncoder 包装 SpringEncoder,可以同时支持 @RequestBody 的 JSON 参数传递 和 multipartFile 文件上传,但需要满足以下条件:
1. 支持的场景
参数类型 编码方式 触发条件
@RequestBody 对象 JSON(application/json) 方法声明中包含 @RequestBody,且未指定 consumes 类型
@RequestPart 文件 multipart/form-data 方法参数中包含 MultipartFile 类型,且声明 consumes = MediaType.MULTIPART_FORM_DATA_VALUE
2. 自动选择编码的逻辑
JSON 编码(SpringEncoder)
当方法参数标记为 @RequestBody 且未强制指定 consumes 类型时,Feign 会优先使用 SpringEncoder 中的 Jackson2JsonHttpMessageConverter 将对象序列化为 JSON。Multipart 编码(SpringFormEncoder)
当方法参数包含 MultipartFile 且声明 consumes = MediaType.MULTIPART_FORM_DATA_VALUE 时,SpringFormEncoder 会自动切换为 multipart/form-data 编码模式。
章末
这里简易将使用到自定义编码配置类的 feign 接口统一放到一个调用类中,不要跟正常调用的方法放一起,这里指定了编码配置可能会影响别的方法
文章到这里就结束了~
往期推荐 > > >
【接口负载】✈️整合 Resilience4j 指定接口负载,避免过载
【SpringBoot】⭐️整合 Redis 实现百万级数据实时排序
【SpringBoot】✈️本地集成支付宝支付功能