Feign 接口实现上传多个文件的坑 - 今日头条

本文由 简悦 SimpRead 转码, 原文地址 www.toutiao.com

还有需求可以通过后台服务通过 Feign 接口方式 ,调用上传文件资源服务。在这过程中,遇到了一些问题,老顾在这里留个 tag,避免小伙伴们也遇到相似

这段时间老顾需要做一个公共的上传文件资源的服务,可以通过前端直接调用上传文件;还有需求可以通过后台服务通过 Feign 接口方式 ,调用上传文件资源服务

在这过程中,遇到了一些问题,老顾在这里留个 tag,避免小伙伴们也遇到相似的问题

https://p3.toutiaoimg.com/origin/pgc-image/c7342e2161c94943aeea6392f8c468e3?from=pc

上面流程是常规的上传文件的 2 种方式,我们下面先来看看,正常的代码

https://p3.toutiaoimg.com/origin/pgc-image/56f472d53a8d4e119f731cf6deb3ae0b?from=pc

文件服务支持单个文件,以及多个文件上传

通过 feign 接口进行上传文件,需要依赖

https://p3.toutiaoimg.com/origin/pgc-image/33c7a0ad94254ebebda8f62648e4e4a7?from=pc

接口定义

https://p3.toutiaoimg.com/origin/pgc-image/1e9077617eca4446a987919a2053aa15?from=pc

上面代码中需定义一个 FileUploadMultipartSupportConfig,如下

https://p3.toutiaoimg.com/origin/pgc-image/4876e7391493451fac53fe394596f6a1?from=pc

调用 Feign 接口,实现上传文件

https://p3.toutiaoimg.com/origin/pgc-image/f0a20e71d3574c3083ecf9e463f2273d?from=pc

在启动执行时,会出现

1
the request was rejected because no multipart boundary was found

分析源码,发现问题出现在

https://p3.toutiaoimg.com/origin/pgc-image/fc10c288c6f74ba6b18f7d55e72a5e56?from=pc

可以看到是 request 中 boundary 的为空,但是我在接受前台的时候有,跨服务的时候丢了。

这个是为什么???

经过排查,发现我们做了 Feign 的头部参数的 FeginInterceptor

https://p3.toutiaoimg.com/origin/pgc-image/e7581e342d8946909fd461a11e2ab4fb?from=pc

当用户提交到微服务 API 时, 分隔符 boundary 是用户那边生成;在 API 通过 fegin 调用其他文件上传微服务时候,也会生成一个新 boundary 分隔符两个导致 boundary 分隔符不同导致微服务那边接受到 MultipartFile 是 null

只需要在转换请求头转发时候过滤掉 “Content-Type” 即可。如下

https://p3.toutiaoimg.com/origin/pgc-image/a21851572f4641b49324573726d39211?from=pc

这样处理的目的就是,Content-Type 不传递

上传多个文件报错,这是为什么呢?主要因为如下代码

https://p3.toutiaoimg.com/origin/pgc-image/52a89b4bf1434f70801e7bdff9da1bf8?from=pc

SpringFormEncoder 类里却没有对文件数组类型的判断,以致不能支持文件数组的上传

我们来看看 SpringFormEncoder 源码

https://p3.toutiaoimg.com/origin/pgc-image/5d1e45929c544e1cb364d6cadcff7c7a?from=pc

在 encode 方法里又只判断了 MultipartFile 类型,没有判断数组类型,底层有对数组的支持但上层却缺少了相应判断

仿照 SpringFormEncoder 源码,只修改 encode 方法;扩展 FormEncoder 支持多文件上传

代码如下:

https://p3.toutiaoimg.com/origin/pgc-image/882a31836f004306a963bd4d9233c6e0?from=pc

然后修改配置类

https://p3.toutiaoimg.com/origin/pgc-image/a4fb615797ee48f983f2d2ade07d2389?from=pc

这样就可以支持 多个文件了

上面两个坑都填了,小伙伴就可以放心用了。

不过老顾发现

1
2
3
4
5
<dependency>
    <groupId>io.github.openfeign.form</groupId>
    <artifactId>feign-form-spring</artifactId>
    <version>3.8.0</version>
</dependency>

在 3.8.0 版本中,已经修复了 坑二的问题

https://p3.toutiaoimg.com/origin/pgc-image/9be35576c0194b208293d700fe72a4a4?from=pc

这样小伙伴就不需要重写了 FormEncoder

推荐阅读

解决 Api 统一格式返回,遗留地返回 String 一个问题

SpringMVC 全局异常方案、源码分析,以及常见的入坑

Spring 多种启动初始化方案,看这篇就够了

来说说 ThreadLocal 内存溢出问题

阿里面试题:强、软、弱、虚引用的特点及应用场景

企业常用的并发编程 Queue 的源码分析

了解 JAVA 中的 SPI 机制,以及数据库驱动插件,这一篇就够了

企业实战之阿里 druid 统一监控方案,你了解吗?

千人千面精准推荐之大白话讲解协同算法(一), 看这篇就够了

企业实战之分布式锁方案一步步的演变

你了解滑动时间窗口吗?Sentinel 核心源码剖析

Sentinel 全局 Feign 默认熔断降级策略的思考

你所不知道的头部参数传递的坑,来吧!抓紧出坑

5 分钟让你理解 K8S 必备架构概念,以及网络模型(一)

5 分钟让你理解 K8S 必备架构概念,以及网络模型(二)

5 分钟让你理解 K8S 必备架构概念,以及网络模型(三)

大厂如何基于 binlog 解决多机房同步 mysql 数据(一)?

大厂如何基于 binlog 解决多机房同步 mysql 数据(二)?

基于 binlog 的 canal 组件有哪些使用场景(三)?

基于 binlog 日志之 canal 企业应用及高可用原理(四)?

可用于大型应用的微服务生态灰度发布如何实现?

一线大厂级别公共 Redis 集群监控,细化到每个项目实例

Sharding-jdbc 的实战入门之水平分表(一)

Sharding-Jdbc 之水平分库和读写分离(二)