We currently have custom code for modifying request body which works but I want to move to the standard ModifyRequestBodyGatewayFilterFactory.
We have a scenario where Spring Cloud Gateway received a GET request and we need call an internal GraphQL api with a POST and a request body.
ModifyRequestBodyGatewayFilterFactory works great if there is a body present in the original request but doesn't apply the rewriteFunction when there is no body on GET requests.
I am using v2.1.2.RELEASE and I have hacked together a change to ModifyRequestBodyGatewayFilterFactory which works for me:
Mono<?> modifiedBody = serverRequest.bodyToMono(inClass)
.defaultIfEmpty("") //added this line
.flatMap(o -> config.rewriteFunction.apply(exchange, o));
I appreciate that the ModifyRequestBodyGatewayFilterFactory is beta, but would it be possible to support adding a body for GET requests in the future?
In general, I don't think it is expected that GET requests would contain a body. There is an interesting thread on this on SO https://stackoverflow.com/questions/978061/http-get-with-request-body.
The change is small enough, that I dont think it would hurt though.
I'm not sure I like the edit.
I think I prefer this (closer to what was there prior to the edit).
.switchIfEmpty((Mono) config.rewriteFunction.apply(exchange, null)); //added this line
I don't like the idea of having a body with an empty string. I also think it might need to be opt-in since it is very unusual.
The original GET doesn't contain a body.
I can add have a go at creating a merge request for this with the opt-in configuration if that would be useful.
@sam-lewis PRs welcome if it is along the lines of my comment.
My interim scheme:
new Predicate copy from ReadBodyPredicateFactory,has all request can match this route。
@Component
public class GwReadBodyPredicateFactory extends AbstractRoutePredicateFactory<GwReadBodyPredicateFactory.Config> {
...
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange,
(serverHttpRequest) -> ServerRequest
.create(exchange.mutate().request(serverHttpRequest)
.build(), messageReaders)
.bodyToMono(inClass)
.doOnNext(objectValue -> exchange.getAttributes().put(
CACHE_REQUEST_BODY_OBJECT_KEY,
objectValue.toString().replaceAll("[\n\t\r'']", ""))) //elegant string
.map(objectValue -> config.getPredicate()
.test(objectValue))
.thenReturn(true));// added this line
...
}
Is it feasible?@spencergibb
I'm not sure this exactly covers the use-case of this issue, but I worked around empty body in usage of modifyRequestBody by testing for null the original body and returning Mono.empty() when null body.
.modifyRequestBody(String.class, String.class,
(webExchange, originalBody) -> {
if (originalBody != null) {
//modify body
[...]
return Mono.just(originalBody);
} else {
return Mono.empty();
}
})
and submitted https://github.com/spring-cloud/spring-cloud-gateway/pull/2000
Most helpful comment
I'm not sure I like the edit.
I think I prefer this (closer to what was there prior to the edit).
I don't like the idea of having a body with an empty string. I also think it might need to be opt-in since it is very unusual.