i have a GatewayFilter.It receives a request,
How do I add the query parameters to the request body as json?
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse response = exchange.getResponse();
ServerHttpRequest request = exchange.getRequest();
BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = getBodyInsert(exchange);
CachedBodyOutputMessage outputMessage = getCachedBodyOutputMessage(exchange);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
//1.checks the signature (omit)
//2. get these parameters remotely
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("calcPackageId", 10000);
paramMap.put("userId", 10001);
paramMap.put("barId", 10002);
String body = JSON.toJSON(paramMap);
//3. todo how to set request body {"calcPackageId":"10000","barId":"10002","userId":"10001"} ??????
//4 forwards the request
return chain.filter(exchange.mutate().request(newRequest).build());
}));
}
//not important
private BodyInserter<Mono<String>, ReactiveHttpOutputMessage> getBodyInsert(ServerWebExchange exchange) {
ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
Mono<String> rawBody = serverRequest.bodyToMono(String.class).map(s -> s);
return BodyInserters.fromPublisher(rawBody, String.class);
}
private CachedBodyOutputMessage getCachedBodyOutputMessage(ServerWebExchange exchange) {
HttpHeaders tempHeaders = new HttpHeaders();
tempHeaders.putAll(exchange.getRequest().getHeaders());
tempHeaders.remove(HttpHeaders.CONTENT_LENGTH);
return new CachedBodyOutputMessage(exchange, tempHeaders);
}
One approach would be injecting a ModifyRequestBodyGatewayFilterFactory
bean into you filter. It's automatically initialized by Spring Cloud Gateway's Autoconfig.
Then, to it's .apply
method, you can pass a RewriteFunction
object. With this you could just create a custom class that implements the RewriteFunction
interface, initialize it with the data you need and then return it as the new body. For example:
public class SomeFilter implements GatewayFilter {
private final ModifyRequestBodyGatewayFilterFactory factory;
public SomeFilter(ModifyRequestBodyGatewayFilterFactory factory) {
this.factory = factory;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Map<String, Integer> someMap = new HashMap<>();
someMap.put("AbC", 100);
ModifyRequestBodyGatewayFilterFactory.Config cfg = new ModifyRequestBodyGatewayFilterFactory.Config();
cfg.setRewriteFunction(String.class, String.class, new SomeRewriteFunction(someMap));
GatewayFilter modifyBodyFilter = factory.apply(cfg);
return modifyBodyFilter.filter(exchange, ch -> Mono.empty())
.then(chain.filter(exchange));
}
}
and the rewrite function:
public class SomeRewriteFunction implements RewriteFunction<String, String> {
private final Map<String, Integer> values;
public SomeRewriteFunction(Map<String, Integer> values) {
this.values = values;
}
@Override
public Publisher<String> apply(ServerWebExchange serverWebExchange, String oldBody) {
/* do things here */
/* example: */
try {
String newBody = new ObjectMapper().writeValueAsString(values);
return Mono.just(newBody);
} catch (Exception e) {
/* error parsing values to json, do something else */
return Mono.just(oldBody);
}
}
}
Other approach is to inject a decorator and then modify its getBody()
method:
public class SomeFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Map<String, Integer> someMap = new HashMap<>();
someMap.put("AbC", 100);
SomeDecorator requestDecorator = new SomeDecorator(exchange.getRequest(), someMap);
return chain.filter(exchange.mutate().request(requestDecorator).build());
}
}
and the decorator:
public class SomeDecorator extends ServerHttpRequestDecorator {
private final Map<String, Integer> values;
public SomeDecorator(ServerHttpRequest delegate, Map<String, Integer> values) {
super(delegate);
this.values = values;
}
@Override
public Flux<DataBuffer> getBody() {
try {
String newBody = new ObjectMapper().writeValueAsString(values);
DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
DefaultDataBuffer buffer = factory.wrap(newBody.getBytes());
return Flux.just(buffer);
} catch (JsonProcessingException e) {
return super.getBody();
}
}
}