我使用Spring 5,Netty和Spring webflux开发和API网关。有时我希望网关停止请求,但我也想读取请求的主体,例如记录它并向客户端返回错误。
我尝试通过订阅正文在WebFilter中执行此操作。
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (enabled) {
logger.debug("gateway is enabled. The Request is routed.");
return chain.filter(exchange);
} else {
logger.debug("gateway is disabled. A 404 error is returned.");
exchange.getRequest().getBody().subscribe();
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().allocateBuffer(0)));
}
}
当我这样做时,它在身体内容很小时起作用。但是当我有一个大的boby时,只读取通量的第一个元素,所以我不能拥有整个身体。知道怎么做吗?
答案 0 :(得分:2)
这里的问题是您在过滤器中手动订阅,这意味着您将从管道的其余部分断开请求的读取。致电subscribe()
会为您提供Disposable
,帮助您管理基础Subscription
。
所以你需要将整个过程连接成一个单独的管道,有点像:
Flux<DataBuffer> requestBody = exchange.getRequest().getBody();
// decode the request body as a Mono or a Flux
Mono<String> decodedBody = decodeBody(requestBody);
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return decodedBody.doOnNext(s -> logger.info(s))
.then(exchange.getResponse().setComplete());
请注意,将整个请求正文解码为Mono
意味着您的网关必须在内存中缓冲整个请求正文。
DataBuffer
故意是低级别类型。如果您想将它解码(即实现示例decodeBody
方法)作为String,您可以使用Spring中的各种Decoder
实现之一,如StringDecoder
。
现在因为这是一个相当大而且复杂的空间,你可以使用和/或看看Spring Cloud Gateway,这样做会更多。
答案 1 :(得分:1)
1。在发布路线中添加“ readBody()”:
builder.routes()
.route("get_route", r -> r.path("/**")
.and().method("GET")
.filters(f -> f.filter(myFilter))
.uri(myUrl))
.route("post_route", r -> r.path("/**")
.and().method("POST")
.and().readBody(String.class, requestBody -> {return true;})
.filters(f -> f.filter(myFilter))
.uri(myUrl))
2。然后您可以在过滤器中获取主体字符串:
String body = exchange.getAttribute("cachedRequestBodyObject");
优势:
无障碍。
无需为后续过程补充身体。
与Spring Boot 2.0.6.RELEASE + Sring Cloud Finchley.SR2 + Spring Cloud Gateway一起使用。