https://kotlinlang.org logo
#ktor
Title
# ktor
v

Vladislav Areshkin [IceRock]

10/08/2021, 1:11 PM
Hello! Can anybody tell is there a way to receive a body of one response twice to avoid
DoubleReceiveException
in ktor-client? Or maybe there are ways to create some kind of feautre/plugin that receives the body at the
HttpReceivePipeline.After
phase, processes the body data and after continues piplene execution unchanged for the response? Is it possible?
1
e

Exterminantus

10/08/2021, 5:53 PM
v

Vladislav Areshkin [IceRock]

10/08/2021, 6:01 PM
Yep, it's for ktor-server. But what about ktor-client?
r

Rustam Siniukov

10/08/2021, 6:56 PM
There is
ResponseObserver
plugin that allows you to read copy of a body. It’s used for
Logging
plugin. Unfortunately, its installation is not that simple, so you may need a plugin that wraps it. Something like this should work
Copy code
companion object MyObserver : HttpClientPlugin<Unit, MyObserver> {
        override val key = AttributeKey<MyObserver>("MyObserve")

        override fun prepare(block: Unit.() -> Unit): MyObserver = this

        override fun install(plugin: MyObserver, scope: HttpClient) {
            val handler: ResponseHandler = { doSomethingWithResponse(it) }
            ResponseObserver.install(ResponseObserver(handler), scope)
        }
    }

    client.install(MyObserver)
👀 1
v

Vladislav Areshkin [IceRock]

10/09/2021, 11:22 AM
The
Logging
feature is the first thing that i looked at 🙂`ResponseObserver` is useful plugin, but it works asynchronously. In my case, I need sequentially: to get a response, handle body of the content, and then using the result of the content processing decide to continue pipeline or, for example, throw an exception.
I made new feature but I'm not sure that the implementation is correct. It's work like this:
Copy code
scope.receivePipeline.intercept(HttpReceivePipeline.After) { response ->
    val charset = response.contentType()?.charset() ?: Charsets.UTF_8
    // Get body from content
    val body = response.content.readRemaining().readText(
        charset = charset
    )

    // Processing body
    val result = handleBody(body)
    if (result) {
        // Just proceed pipeline
        val byteChannel = ByteReadChannel(
            body.toByteArray(charset)
        )
        proceedWith(context.wrapWithContent(byteChannel).response)
    } else {
        throw Exception()
    }
}
r

Rustam Siniukov

10/11/2021, 12:12 PM
I suggest you to use
responsePipeline
instead, since it’s responsible for handling body of a response. Otherwise your code should work.
👍 1
e

Exterminantus

10/11/2021, 12:12 PM
Okay
7 Views