Question
Hi guys I want to create a simple filter to log request and responses, their headers and body for all requests(GET/POST/PUT/DELETE) passing through the gateway.
Is it possible to do this?
I cannot find a good solution to read the request/response body
Please note that I have a working function for this:
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String requestMethod = exchange.getRequest().getMethod().toString();
String path = exchange.getRequest().getPath().toString();
String headers = exchange.getRequest().getHeaders().toSingleValueMap().toString();
//TODO: propper read request body when available
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
String responseHeaders = exchange.getRequest().getHeaders().toSingleValueMap().toString();
int status = exchange.getResponse().getStatusCode().value();
//TODO: propper read response body when available
}));
}
What you have looks fine for headers (though you'll loose multi value headers).
For the request/response body I wouldn't recommend doing it 100% of the time since you'll have to buffer all requests/responses into memory. See the Modify filters here https://github.com/spring-cloud/spring-cloud-gateway/tree/master/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite
I custom a plugin project for spring-cloud-gateway.
You can take a look at it . Issues and PR welcome.
https://github.com/chenggangpro/spring-cloud-gateway-plugin
BTW: Read Request And Response cost a lot of memory.Wouldn't recommend doing it 100% of the time.
@chenggangpro I will take a look at it in the weekend :) thanks
@spencergibb thanks for the feedback.
We can close this topic
Hi!
I need to get the request body content for routes defined in the application.yml
If I use a custom RouteLocator the
exchange.getAttribute("cachedRequestBodyObject")
is filled for all requests (also the one out of the yml)
you can find the code here
https://gist.github.com/matzegebbe/bf631b2d3ab6d55f58f4b6c1d3511189
curl -H "x-debug: /nginx/" -X POST -d "{'data':'fooBar'}" http://localhost:8080/nginx/
with application.yml
- id: nginx
uri: http://localhost:8082
predicates:
- Path=/nginx/**
filters:
- StripPrefix=1
gives me the log
n.h.apigateway.ApiGatewayApplication : Started ApiGatewayApplication in 3.666 seconds (JVM running for 4.311)
n.h.a.filter.RequestResponseLogFilter : Request Scheme:http,Path:/nginx/
n.h.a.filter.RequestResponseLogFilter : Request Method:POST,IP:/0:0:0:0:0:0:0:1%0:48774,Host:localhost
n.h.a.filter.RequestResponseLogFilter : Request ContentType:application/x-www-form-urlencoded,Content Length:17
n.h.a.filter.RequestResponseLogFilter : Request Body:{'data':'fooBar'}
n.h.a.filter.RequestResponseLogFilter : Response HttpStatus:200 OK
n.h.a.filter.RequestResponseLogFilter : Response ContentType:null,Content Length:-1
n.h.a.filter.RequestResponseLogFilter : Response Original Path:/nginx/,Cost:15 ms
n.h.a.filter.RequestResponseLogFilter : Response:<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.17.2</center>
</body>
</html>
Here is a variant that use modify filters to capture and log request and response body
@Bean
public RouteLocator myRouteSavingRequestBody(RouteLocatorBuilder builder) {
return builder.routes()
.route("my-route-id",
p -> p
.path("/v2/**") //your own path filter
.filters(f -> f
.modifyResponseBody(String.class, String.class,
(webExchange, originalBody) -> {
if (originalBody != null) {
logger.debug("Response body {}", originalBody);
return Mono.just(originalBody);
} else {
return Mono.empty();
}
})
.modifyRequestBody(String.class, String.class,
(webExchange, originalBody) -> {
if (originalBody != null) {
logger.debug("Request body {}", originalBody);
return Mono.just(originalBody);
} else {
return Mono.empty();
}
})
)
.uri("https://myuri.org")
)
.build();
}
Most helpful comment
Hi!
I need to get the request body content for routes defined in the application.yml
If I use a custom RouteLocator the
is filled for all requests (also the one out of the yml)
you can find the code here
https://gist.github.com/matzegebbe/bf631b2d3ab6d55f58f4b6c1d3511189
with application.yml
gives me the log