【Spring-Cloud-Gateway】modifyRequestBody处理form-data时遇到的大坑
-
版本:Hoxton.SR8
-
SpringBoot版本:2.3.3.RELEASE
需求描述
我所开发的平台,主要是以post application/json进行交互。
但个别页面需要form-data格式,比如传输文件。所以需要开发针对form-data格式的网关路由。同时网关需要从form-data信息中解析出一些字段进行过滤处理。所以就遇到了当已byte[]方式处理数据时,业务接口就无法成功解析form-data的数据格式。
事件原因:
因业务需要,需要对form-data进行解析,获取到字段,然后将信息继续传递或增加新字段后传递下去。
按照如下写法,会出现下游接口无法有效获取参数及文件的情况。代码如下:
@Bean
public RouteLocator route1(RouteLocatorBuilder builder) {
return builder.routes()
.route("xxx", r -> r
.order(1)
// 请求path
.path("/**")
.and()
// 请求host约束
.host("**")
.and()
// header约束
.header("Content-Type", ".*form-data.*")
.filters(f -> f
.modifyRequestBody(byte[].class, byte[].class, MediaType.MULTIPART_FORM_DATA_VALUE, (exchange, bs) -> apiCheckFilter.requestFilter(exchange, bs)
)
// 目标url(我这个项目是非微服务的,这里的差异可以忽略)
.uri(apiUrl)
)
.build();
}
filter代码如下:
public Mono<byte[]> requestFilter(ServerWebExchange exchange, final byte[] bytes) {
// 省略业务逻辑代码
// ...
// ...
// ...
return Mono.just(bytes);
}
问题原因:
form-data格式,依赖http header中的 Content-Type 字段,字段中包含ContentType以及boundary。
一个form-data数据转换为字符串,大概长这样:
--raegreagrtsshtrdhtresgarwetr-blah
Content-Disposition: form-data; name="param1"
hello, world
--raegreagrtsshtrdhtresgarwetr-blah
Content-Disposition: form-data; name="param2"
42
--raegreagrtsshtrdhtresgarwetr-blah
Content-Disposition: form-data; name="param3"
ABCDEFG
--raegreagrtsshtrdhtresgarwetr-blah--
其中“–raegreagrtsshtrdhtresgarwetr-blah”就是boundary,可以简单看做请求标识以及分割线的作用。
但modifyRequestBody第三个参数,会将请求Content-Type进行重写,而form-data依赖的boundary却未被写入,所以导致下游无法解析form-data的格式。
所以只需要去掉该Content-Type的参数声明,让其自动处理即可。代码如下:
@Bean
public RouteLocator route1(RouteLocatorBuilder builder) {
return builder.routes()
.route("xxx", r -> r
.order(1)
// 请求path
.path("/**")
.and()
// 请求host约束
.host("**")
.and()
// header约束
.header("Content-Type", ".*form-data.*")
.filters(f -> f
.modifyRequestBody(byte[].class, byte[].class, (exchange, bs) -> apiCheckFilter.requestFilter(exchange, bs)
)
.uri(apiUrl)
)
.build();
}
public Mono<byte[]> requestFilter(ServerWebExchange exchange, final byte[] bytes) {
// 省略业务逻辑代码
return Mono.just(bytes);
}