如何使用 Spring Cloud Gateway 在 GatewayFilter 中设置请求正文
How to set request body in GatewayFilter with Spring Cloud Gateway
我有一个GatewayFilter.It收到一个请求,
- 先检查签名(代码省略)
- 查询一些需要的参数
- 将它们添加到请求中
- 终于转发了请求
如何将查询参数添加到请求正文中作为 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);
}
一种方法是将 ModifyRequestBodyGatewayFilterFactory
bean 注入过滤器。它由 Spring Cloud Gateway 的 Autoconfig 自动初始化。
然后,您可以向它的 .apply
方法传递一个 RewriteFunction
对象。有了这个,你可以创建一个自定义的 class 来实现 RewriteFunction
接口,用你需要的数据初始化它,然后 return 它作为新的主体。例如:
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));
}
}
和重写函数:
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);
}
}
}
另一种方法是注入一个装饰器,然后修改它的getBody()
方法:
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());
}
}
和装饰者:
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();
}
}
}
我有一个GatewayFilter.It收到一个请求,
- 先检查签名(代码省略)
- 查询一些需要的参数
- 将它们添加到请求中
- 终于转发了请求
如何将查询参数添加到请求正文中作为 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);
}
一种方法是将 ModifyRequestBodyGatewayFilterFactory
bean 注入过滤器。它由 Spring Cloud Gateway 的 Autoconfig 自动初始化。
然后,您可以向它的 .apply
方法传递一个 RewriteFunction
对象。有了这个,你可以创建一个自定义的 class 来实现 RewriteFunction
接口,用你需要的数据初始化它,然后 return 它作为新的主体。例如:
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));
}
}
和重写函数:
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);
}
}
}
另一种方法是注入一个装饰器,然后修改它的getBody()
方法:
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());
}
}
和装饰者:
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();
}
}
}