When using the Spring Cloud Gateway, you often need to get the Request body for logging, signature verification, encryption and decryption, and so on.
Online materials, solutions are all over the place. So two methods that have been proven and are already available online have been organized, both based on official source code extensions.
The Spring Cloud Gateway version used in this article is 2.1.1.release.
ModifyRequestBodyGatewayFilterFactory
ModifyRequestBodyGatewayFilterFactory in official documents is introduced as follows:
This filter can be used to modify the request body before it is sent downstream by the Gateway.
The request body is used to modify the request body, so if you can modify it, you can get it.
The Java configuration
A simple configuration is as follows:
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_body", r -> r.path("/post_json")
.filters(f -> f.modifyRequestBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE, (exchange, s) -> Mono.just(s)))
.uri("lb://waiter"))
.build();
}
Copy the code
Notice that the modifyRequestBody method has four parameters
- InClass: Type of request body before conversion.
- OutClass: Converted request Body type.
- NewContentType: Converted ContentType.
- RewriteFunction: Method of rewriting the body. This is where you get the Request body.
Of particular note are the types of inClass and outClass, which will report an error if set incorrectly.
summary
advantages
- You can not only read the Request body, but also modify it.
disadvantages
- If you only need to fetch and do not need to modify, using this filter is a bit heavy.
- If multiple filters need to be read, the official version does not support caching and cannot be read for multiple times. (Not primarily for that either)
ReadBodyPredicateFactory (recommended)
ReadBodyPredicateFactory is a predicate that reads and determines whether the Request Body matches. Only in the official documents are not explained, but does not affect the use.
There are comments in the code like this:
We can only read the body from the request once, once that happens if we try to read the body again an exception will be thrown. The below if/else caches the body object as a request attribute in the ServerWebExchange so if this filter is run more than once (due to more than one route using it) we do not try to read the request body multiple times
We can only read the request body from the request once, and if we read it again, it will be thrown incorrectly. The following code caches the Request body as a Request attribute in ServerWebExchange. If the filter is run multiple times, there is no need to read the Request body multiple times.
The Java configuration
A simple configuration is as follows:
@Autowired
private LogRequestBodyGatewayFilterFactory logRequestBodyGatewayFilterFactory;
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_json", r -> r.path("/post_json")
.and()
.readBody(String.class, requestBody -> true)
.filters(f -> f.filter(logRequestBodyGatewayFilterFactory.apply(new LogRequestBodyGatewayFilterFactory.Config())))
.uri("lb://waiter"))
.build();
}
Copy the code
Notice the readBody method, which takes two parameters
- InClass: The type of the request body before the conversion, which will be converted to this type.
- Predicate: Predicate judgment. You can always return true if you want to use it for records. False will result in a route mismatch.
Of particular note is the type of inClass, which will report an error if set incorrectly.
A GatewayFilterFactory LogRequestBodyGatewayFilterFactory is custom, Since ReadBodyPredicateFactory caches the Request body to ServerWebExchange, all you need to do is fetch it from ServerWebExchange.
@Slf4j
@Component
public class LogRequestBodyGatewayFilterFactory extends
AbstractGatewayFilterFactory<LogRequestBodyGatewayFilterFactory.Config> {
private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
public LogRequestBodyGatewayFilterFactory(a) {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String requestBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
log.info(requestBody);
return chain.filter(exchange);
};
}
public static class Config {}}Copy the code
summary
advantages
- Read once and fetch many times.
- Can be used as a predicate to accept only the request body of the specified type.
extension
The official documentation states that neither of these methods can be handled through configuration files, which is not flexible enough to meet practical needs.
Extend up actually is not very difficult, as long as can’t be through the contents of the configuration file is configured to block, to RewriteFunction ModifyRequestBodyGatewayFilterFactory is, For ReadBodyPredicateFactory is the Predicate.
There are two possible solutions
- Write the logic to death in your code and remove the configuration property.
- Change the original interface-based implementation to bean injection by injecting beans. Similar to the
RequestRateLimiterGatewayFilterFactory
In the injectionkeyResolver
.
The first method is not specified here, but you can implement it yourself.
With the second approach, the following configuration is equivalent to the Java Config written in the ReadBodyPredicateFactory section above.
spring.cloud.gateway.routes[0].id=rewrite_json
spring.cloud.gateway.routes[0].predicates[0]=Path=/post_json
spring.cloud.gateway.routes[0].predicates[1].name=ReadBodyPredicateFactory
spring.cloud.gateway.routes[0].predicates[1].args.inClass=#{T(String)}
spring.cloud.gateway.routes[0].predicates[1].args.predicate=#{@testPredicate}
spring.cloud.gateway.routes[0].filters[0].name=LogRequestBody
spring.cloud.gateway.routes[0].uri=lb://waiter
Copy the code
You need to provide a bean, the testPredicate in the configuration file
@Component
public class TestPredicate implements Predicate {
@Override
public boolean test(Object o) {
return true; }}Copy the code
It mainly utilizes SpEL, injection types, and beans.
In the future
Now both ModifyRequestBodyGatewayFilterFactory ReadBodyPredicateFactory in 2.1.1. The RELEASE or BETA version, but in 2.2.0. RC1, The comments for BETA versions of both classes are gone, so feel free to use them.
reference
-
Spring Cloud Gateway 2.1.1.RELEASE Reference Doc
-
Spring Cloud (19) : Spring Cloud Gateway (read and modify Request Body)
-
SpringCloud Gateway gets postreQuest body(Request Body)
See here must be true love, follow the wechat public number [Simple and Simple Spring] the first time to get updates.