SpringCloud-Gateway对multipart/form-data等其他POST请求类型的body体进行多次打开
本次代码仅在以下版本中测试通过
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 .