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

<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只能打开一次。

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内容进行缓存,之后便可以在方法里进行调用

@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;
    }
}

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;
    }
}

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

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


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐