最近网上查询关于spring cloud gateway获取request的各种资料,尝试后发现都存在一些问题,结合几篇文章,翻看了一部分源码,总结出了一套个人认为稍微好一些的解决方法(还是有些问题)。
@Slf4j @Component public class PostBodyGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); HttpHeaders headers = request.getHeaders(); String method = request.getMethodValue(); String contentType = headers.getFirst("Content-Type"); //去除文件上传 if (!Strings.isNullOrEmpty(contentType) && contentType.startsWith("multipart/form-data")) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } if ("POST".equalsIgnoreCase(method)) { //判断是否为POST请求 ServerRequest serverRequest = new DefaultServerRequest(exchange); // Flux<String> flux = serverRequest.bodyToFlux(String.class); // ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) { // private StringBuilder respBody=new StringBuilder(); // @Override // public HttpHeaders getHeaders() { // HttpHeaders httpHeaders = new HttpHeaders(); // httpHeaders.putAll(super.getHeaders()); // httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); // return httpHeaders; // } // @Override // public Flux<DataBuffer> getBody() { // return flux.map(body -> { // respBody.append(body).append("\n"); // NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false)); // return nettyDataBufferFactory.wrap(body.getBytes()); // }).doOnComplete(()-> log.info("\n请求url={},请求参数={}\n,headers{}",super.getPath().value(),respBody.toString(),super.getHeaders())); // } // }; // return chain.filter(exchange.mutate().request(newRequest).build()); Mono<String> bodyToMono = serverRequest.bodyToMono(String.class); return bodyToMono.flatMap(body -> { log.info(body); ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) { @Override public HttpHeaders getHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); return httpHeaders; } @Override public Flux<DataBuffer> getBody() { NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false)); DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(body.getBytes()); return Flux.just(bodyDataBuffer); } }; return chain.filter(exchange.mutate().request(newRequest).build()); }); } return chain.filter(exchange); }
代码参考了源码类(ModifyRequestBodyGatewayFilterFactory),get获取request参数在这里不再讨论,网上资料很多哈。着重说下post获取方式
Mono<String> bodyToMono = serverRequest.bodyToMono(String.class); return bodyToMono.flatMap(body -> { log.info(body); ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) { @Override public HttpHeaders getHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); return httpHeaders; } @Override public Flux<DataBuffer> getBody() { NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false)); DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(body.getBytes()); return Flux.just(bodyDataBuffer); } }; return chain.filter(exchange.mutate().request(newRequest).build()); });
通过上面的代码可以解决请求体过长被截断的问题,并且可以在其中修改请求参数,做一些业务相关逻辑(比如参数校验,参数增删等),但是这种方式有个问题是当请求体为空时获取不到响应体。下面这段代码可以解决这个问题,但是只能做一些请求日志记录。
Flux<String> flux = serverRequest.bodyToFlux(String.class); // ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) { // private StringBuilder respBody=new StringBuilder(); // @Override // public HttpHeaders getHeaders() { // HttpHeaders httpHeaders = new HttpHeaders(); // httpHeaders.putAll(super.getHeaders()); // httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); // return httpHeaders; // } // @Override // public Flux<DataBuffer> getBody() { // return flux.map(body -> { // respBody.append(body).append("\n"); // NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false)); // return nettyDataBufferFactory.wrap(body.getBytes()); // }).doOnComplete(()-> log.info("\n请求url={},请求参数={}\n,headers={}",super.getPath().value(),respBody.toString(),super.getHeaders())); // } // }; // return chain.filter(exchange.mutate().request(newRequest).build());
因为请求体会被截断,这里用stringbuider连接
ps:对flux这种操作还不太习惯,另外感觉spring cloud gateway的坑还是有点多的- -。
如果各位有更好的解决方法,希望互相交流一下。。。