4

I have a POST Gateway filter that I want to modify the response body with the response of a separate webclient request within the gateway filter. I am able to get as far as sending the WebClient().create().post().exchange() within my custom filter. I can see this in my logs

onStateChange(POST{uri=/test, connection=PooledConnection{channel=[id: 0x38eb2b4f, L:/127.0.0.1:51643 - R:localhost/127.0.0.1:9000]}}, [request_prepared])

and

onStateChange(POST{uri=/test, connection=PooledConnection{channel=[id: 0x38eb2b4f, L:/127.0.0.1:51643 - R:localhost/127.0.0.1:9000]}}, [request_sent])

the connection hangs here and doesn't complete.

here is my custom filter code

class PostProxyGatewayFilterFactory : AbstractGatewayFilterFactory<PostProxyGatewayFilterFactory.Params>(Params::class.java) {
    override fun apply(params: Params): GatewayFilter {
        val cachedBody = StringBuilder()
        return GatewayFilter { exchange: ServerWebExchange, chain: GatewayFilterChain ->
            chain.filter(exchange).then(
                    executeRequest(cachedBody,exchange, params)
                            .map {
                                val mr = ResponseHandler(exchange)
                                mr.mutateResponse(it.body.toString())
                            }.flatMap{
                                it
                            }
            ) }
    }

    data class Params(
            val urlPath: String = "",
    )

    private fun cache(cachedBody: StringBuilder, buffer: DataBuffer) {
        cachedBody.append(Charsets.UTF_8.decode(buffer.asByteBuffer())
                .toString())
    }
    private fun executeRequest(cachedBody: StringBuilder, exchange: ServerWebExchange, params: PostProxyGatewayFilterFactory.Params): Mono<ResponseEntity<JsonNode>>{
        val request = when(exchange.request.method){
            HttpMethod.PUT -> WebClient.create().put().uri(params.urlPath).body(BodyInserters.fromDataBuffers(exchange.request.body.doOnNext{ cache(cachedBody, it)}))
            HttpMethod.POST -> WebClient.create().post().uri(params.urlPath).body(BodyInserters.fromDataBuffers(exchange.request.body.doOnNext{ cache(cachedBody, it)}))
            HttpMethod.GET -> WebClient.create().get().uri(params.urlPath)
            HttpMethod.DELETE -> WebClient.create().delete().uri(params.urlPath)
            else -> throw Exception("Invalid request method passed in to the proxy filter")
        }
        return request.headers { it.addAll(exchange.request.headers) }
                .exchange()
                .flatMap{
                    it.toEntity(JsonNode::class.java)
                }
    }
}

here is my ResponseHandler class

class ResponseHandler(val delegate: ServerWebExchange) {
     fun mutateResponse(body: String): Mono<Void> {
        val bytes: ByteArray = body.toByteArray(StandardCharsets.UTF_8)
        val buffer: DataBuffer = delegate.response.bufferFactory().wrap(bytes)
        return delegate.response.writeWith(Flux.just(buffer))
    }
}

here is application.yml

- id: proxy
  uri: http://${HOST:localhost}:${PORT:9000}
  predicates:
  - Path=/proxy/**
  filters:
  - RewritePath=/test(?<segment>/?.*), $\{segment}
  - name: PostProxy
  args:
    proxyBasePath: http://localhost:9000/thisSecond

So the idea is to send request to localhost:9001/test/thisFirst (proxied to localhost:9000/thisFirst which does happen successfully),get this response back and do nothing with this response, make WebClient request to localhost:9000/thisSecond via executeRequest() ,return this response, and then use that response as the new exchange.response body. I am also not sure if ResponseHandler is correct as executeRequest() never finishes. This would be part 2 of the question once I can resolve why executeRequest() never finishes.

spencergibb
  • 24,471
  • 6
  • 69
  • 75
Addison Joseph
  • 126
  • 2
  • 15

0 Answers0