'Change request body in ServerHttpRequestDecorator using AbstractGatewayFilterFactory - Webflux
Spring Boot Version: 2.5.1, Spring Cloud Version: 2020.0.3
Hello guys !!!
I need your help ...
My question is that I can't modify the request body in spring gateway. Follow:
I have a MobileGatewayFilterFactory class that extends from AbstractGatewayFilterFactory where the apply method returns a custom filter: MobileGatewayFilter.
@Component
class MobileGatewayFilterFactory :
AbstractGatewayFilterFactory<MobileGatewayFilterFactory.Config>(Config::class.java),
Ordered {
override fun apply(config: Config): GatewayFilter {
logger.info { "Loading MobileGatewayFilter with config ${config.className}, ${config.execution}, ${config.custom}" }
return MobileGatewayFilter(config)
}
override fun getOrder(): Int {
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1
}
data class Config(
val className: String,
val execution: String,
val custom: String?
)
}
So, inside the MobileGatewayFilter class I implement the business rules to determine which filter is running: PRE or POST filter. This is done in the filter method of the MobileGatewayFilter class where there is a condition to determine the type of decoration being executed, using reflection. If it is a request, the ServerHttpRequestDecorator is executed and a ServerHttpResponseDecorator otherwise.
class MobileGatewayFilter(private val config: MobileGatewayFilterFactory.Config) : GatewayFilter, Ordered {
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
return when (config.execution) {
"PRE" -> chain.filter(exchange.mutate().request(decoratorRequest(exchange)).build())
"POST" -> chain.filter(exchange.mutate().response(decoratorResponse(exchange)).build())
else -> chain.filter(exchange)
}
}
override fun getOrder(): Int {
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1
}
private fun decoratorResponse(exchange: ServerWebExchange): ServerHttpResponse {
val aClass = Class.forName(config.className)
val obj = aClass.getConstructor(ServerHttpResponse::class.java, MobileGatewayFilterFactory.Config::class.java)
return obj.newInstance(exchange.response, config) as ServerHttpResponseDecorator
}
private fun decoratorRequest(exchange: ServerWebExchange): ServerHttpRequest {
val aClass = Class.forName(config.className)
val obj = aClass.getConstructor(ServerHttpRequest::class.java, MobileGatewayFilterFactory.Config::class.java)
return obj.newInstance(exchange.request, config) as ServerHttpRequestDecorator
}
}
Furthermore, I have a CustomerDataBodyDecorator that extends the ServerHttpRequestDecorator and overrides the getBody method. The getBody method is where the request body must be modified.
class CustomerDataBodyDecorator(
private val exchange: ServerHttpRequest,
private val config: MobileGatewayFilterFactory.Config
) : ServerHttpRequestDecorator(exchange) {
override fun getBody(): Flux<DataBuffer> {
logger.info { "getBody chamado ..." }
val body: Flux<DataBuffer> = exchange.body
var requestData = ""
body.subscribe {
val content = ByteArray(it.readableByteCount())
it.read(content)
DataBufferUtils.release(it)
requestData = String(content, Charset.forName("UTF-8"))
logger.info { "Request: $requestData" }
}
val factory = DefaultDataBufferFactory()
val buffer = factory.wrap(requestData.toByteArray())
return Flux.just(buffer)
}
}
However, the above code doesn't work because the return is executed first with empty requestData and after subscribe method is executed. I know that in Webflux the subscribe method is necessary to indicate to the publisher the information consumption needs
application.yml
id: opengw-mobile-simulation
uri: ${custom.resources.opengw}
predicates:
- Path=/opengw/v1/mobile/simulation
filters:
- name: Mobile
args:
className: br.com.decorator.CustomerDataBodyDecorator
execution: PRE
custom: ${custom.resources.customer}
- RewritePath=/opengw/v1/(?<segment>/?.*), /$\{segment}
I read several topics here but I couldn't find a solution that worked.
How can I read and then modify the request body of the Flux object in this scenario?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|