上传文件调用外部服务报错: not a type supported by this encoder
查看SpringFormEncoder类的源码:
1 public class SpringFormEncoder extends FormEncoder
2 {
3
4 public SpringFormEncoder()
5 {
6 this(((Encoder) (new feign.codec.Encoder.Default())));
7 }
8
9 public SpringFormEncoder(Encoder delegate)
10 {
11 super(delegate);//调用父类的构造方法
12 MultipartFormContentProcessor processor = (MultipartFormContentProcessor)getContentProcessor(ContentType.MULTIPART);
13 processor.addWriter(new SpringSingleMultipartFileWriter());
14 processor.addWriter(new SpringManyMultipartFilesWriter());
15 }
16
17 public void encode(Object object, Type bodyType, RequestTemplate template)
18 throws EncodeException
19 {
20 if(!bodyType.equals(org/springframework/web/multipart/MultipartFile))
21 {
22 super.encode(object, bodyType, template);//调用FormEncoder对应方法
23 return;
24 } else
25 {
26 MultipartFile file = (MultipartFile)object;
27 java.util.Map data = Collections.singletonMap(file.getName(), object);
28 super.encode(data, MAP_STRING_WILDCARD, template);
29 return;
30 }
31 }
32 }
可以发现SpringFormEncoder的encode方法当传送的对象不是MultipartFile的时候,就会调用super.encode, 也就是FormEncoder的encode方法。
FormEncoder类的部分源码:
1 public FormEncoder()
2 {
3 this(((Encoder) (new feign.codec.Encoder.Default())));
4 }
5
6 public FormEncoder(Encoder delegate)
7 {
8 _flddelegate = delegate;
9 List list = Arrays.asList(new ContentProcessor[] {
10 new MultipartFormContentProcessor(delegate), new UrlencodedFormContentProcessor()
11 });
12 processors = new HashMap(list.size(), 1.0F);
13 ContentProcessor processor;
14 for(Iterator iterator = list.iterator(); iterator.hasNext(); processors.put(processor.getSupportedContentType(), processor))
15 processor = (ContentProcessor)iterator.next();
16
17 }
18
19 public void encode(Object object, Type bodyType, RequestTemplate template)
20 throws EncodeException
21 {
22 String contentTypeValue = getContentTypeValue(template.headers());//这里会去到@PostMapping中consumes的值,所以参数需要传对象时指定一下consumes
23 ContentType contentType = ContentType.of(contentTypeValue);//为啥指定consumes,是因为不指定就是application/x-www-form-urlencoded,而且processors中也包含,为啥包含见FormEncoder的构造函数
24 if(!MAP_STRING_WILDCARD.equals(bodyType) || !processors.containsKey(contentType))
25 {
26 _flddelegate.encode(object, bodyType, template);//_flddelegate是啥呢,是SpringFormEncoder传递过来,也就是new Encoder.Default()
27 return;
28 }
29 Charset charset = getCharset(contentTypeValue);
30 Map data = (Map)object;
31 try
32 {
33 ((ContentProcessor)processors.get(contentType)).process(template, charset, data);
34 }
35 catch(Exception ex)
36 {
37 throw new EncodeException(ex.getMessage());
38 }
39 }
FormEncoderr的encode方法当传送的对象是json格式的字符串的时候,就会调用 _flddelegate.encode,即Encoder.Default的encode方法,而这个Encoder.Default的encode方法判断传送的类型不是String或者byte[],就会抛异常
1 public interface Encoder
2 {
3 public static class Default
4 implements Encoder
5 {
6
7 public void encode(Object object, Type bodyType, RequestTemplate template)
8 {
9 if(bodyType == java/lang/String)
10 template.body(object.toString());
11 else
12 if(bodyType == [B)
13 template.body((byte[])(byte[])object, null);
14 else
15 if(object != null)//当我们用对象传递参数的时候,会走这里
16 throw new EncodeException(String.format("%s is not a type supported by this encoder.", new Object[] {
17 object.getClass()
18 }));
19 }
20
21 public Default()
22 {
23 }
24 }
25
26
27 public abstract void encode(Object obj, Type type, RequestTemplate requesttemplate)
28 throws EncodeException;
29
30 public static final Type MAP_STRING_WILDCARD = Util.MAP_STRING_WILDCARD;
31
32 }
解决方案一:继续使用前面提到的方案,如果引用该配置类的FeignClient中,没有使用实体类作为参数的接口,则去掉配置类上的注解@Configuration就可以了,去掉注解@Configuration之后,该配置就只对通过configuration属性引用该配置的FeignClient起作用(或者将该文件上传接口单独放到一个FeignClient中,去掉配置类上的注解@Configuration)。
方案一只支持文件上传,如果引用该配置的FeignClient中有使用实体类作为参数接收的接口,则调用该接口时会抛异常。
解决方案二:继续使用前面提到的方案,将配置文件修改为如下:
1 @Configuration
2 class MultipartSupportConfig {
3 @Autowired
4 private ObjectFactory<HttpMessageConverters> messageConverters;
5
6 @Bean
7 public Encoder feignFormEncoder() {
8 return new SpringFormEncoder(new SpringEncoder(messageConverters));
9 }
10 }
方案二既支持文件上传也支持实体类作为参数接收。
|