ktorio / ktor

Framework for quickly creating connected applications in Kotlin with minimal effort
https://ktor.io
Apache License 2.0
13.09k stars 1.07k forks source link

[Question] Override/Add Headers to response to ktor client #1257

Open jrocharodrigues opened 5 years ago

jrocharodrigues commented 5 years ago

Hi,

I'm trying to force the cache of some responses, that have no cache headers, using ktor client.

In okhttp client i can add an interceptor and change the response headers to force the response to be cached.

I tried to do the same in ktor, creating an feature, adding an interceptor to the receiving pipeline, but i'm not finding an way to override the headers on the response. Is there an way to do it?

I also tried making a custom cache feature, based on the HttpCache provided, but most of the classes needed to that are internal, an due to that i could not achieve the result i needed.

Thanks in advance

e5l commented 5 years ago

Hi @jrocharodrigues, thanks for the report.

As temp solution you can use: response.call.save() method.

https://api.ktor.io/1.2.3/io.ktor.client.call/save.html

jrocharodrigues commented 5 years ago

Hi, Thanks for the prompt answer.

I've tried saving the the response with response.call.save() , to reuse in the following requests, but when i try to reuse it later i get the exception: io.ktor.client.call.DoubleReceiveException: Response already received: io.ktor.client.call.SavedHttpCall@e0ce06c

I'm probably missing something simple, but i'm not getting there...

Heres the revelant code to see if anyone can help:

 override fun install(feature: ForcedCache, scope: HttpClient) {
            val CachePhase = PipelinePhase("Cache")
            scope.sendPipeline.insertPhaseAfter(HttpSendPipeline.State, CachePhase)

            scope.sendPipeline.intercept(CachePhase) { content ->
                if (content !is OutgoingContent.NoContent) return@intercept
                if (context.method != HttpMethod.Get || !context.url.protocol.canStore()) return@intercept

                val cachedResponse = feature.findResponse(context, content)
                if (cachedResponse != null ) {
                    finish()
                    proceedWith(cachedResponse.call)

                    return@intercept
                }

                return@intercept
            }

            scope.receivePipeline.intercept(HttpReceivePipeline.State) { response ->
                if (context.request.method != HttpMethod.Get) return@intercept

                if (response.status.isSuccess()) {
                    val savedCall = response.call.save()
                    feature.cacheResponse(savedCall)
                    proceedWith(savedCall.response)
                    return@intercept
                }

            }
        }

Thank you

oleg-larshin commented 4 years ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.