SpringCloud-Gateway对multipart/form-data等其他POST请求类型的body体进行多次打开

algorain

本次代码仅在以下版本中测试通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>

这几天在用gateway进行鉴权校验的时候遇到很多坑,以前使用的都是x-www-form-urlencoded这种格式的Body,很容易就可以用gateway打开进行操作,但这次因为涉及到图片上传,所以请求格式变了,打开的过程变得非常曲折。

先是找到了下面这种办法,确实可以打开并获取body里的内容,而且还是非常规则的类型,不需要二次提取,formData即是我们想要的内容,后来在路由之后的controller中发现body里没有数据了,原来gateway只能打开一次。

1
2
3
4
5
6
7
8
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType)) {
return exchange.getMultipartData().flatMap(formData->{
exchange.getAttributes().put(GateWayFilterDict.FORM_DATA_ATTR,formData);
return chain.filter(exchange.mutate().build());
});
}

后来换成了这个样子,先使用GlobalFilter对body内容进行缓存,之后便可以在方法里进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component
public class CacheBodyGlobalFilter implements Ordered, GlobalFilter {

public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (exchange.getRequest().getHeaders().getContentType() == null) {
return chain.filter(exchange);
} else {
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
DataBufferUtils.retain(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);

return chain.filter(exchange.mutate().request(mutatedRequest).build());
});
}
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class VerificationFilter implements GatewayFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

String bodyContent = resolveBodyFromRequest(exchange.getRequest());

return chain.filter(exchange);
}

public static String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest){
//获取请求体
Flux<DataBuffer> body = serverHttpRequest.getBody();
StringBuilder sb = new StringBuilder();

body.subscribe(buffer -> {
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
// DataBufferUtils.release(buffer);
String bodyString = new String(bytes, StandardCharsets.UTF_8);
sb.append(bodyString);
});
return formatStr(sb.toString());
}

/**
* 去掉空格,换行和制表符
* @param str
* @return
*/
private static String formatStr(String str){
if (str != null && str.length() > 0) {
Pattern p = Pattern.compile("\\s*\t\r\n");
Matcher m = p.matcher(str);
return m.replaceAll("");
}
return str;
}

@Override
public int getOrder() {
return 1;
}
}

这里是提取出来的内容,需要根据规则进行二次加工,但不复杂

1
2
3
----------------------------582918735041218588371746Content-Disposition:form-data;name="appKey"4324----------------------------582918735041218588371746Content-Disposition:form-data;name="appSecret"43244----------------------------582918735041218588371746--


  • Title: SpringCloud-Gateway对multipart/form-data等其他POST请求类型的body体进行多次打开
  • Author: algorain
  • Created at: 2020-11-10 14:19:24
  • Updated at: 2023-05-14 21:39:50
  • Link: http://www.rain1024.com/2020/11/10/springcloud-gateway对multipart-form-data等其他post请求类型的body体进行多次打开/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments