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

Lubomir Pisk

01/23/2023, 9:44 PM
Hello, I need to read content (copy of ByteReadChannel) of response inside implementation of HttpSendInterceptor. But I didn't find solution that works. I tried this: val contentCopy = _ByteChannel_().apply { response.content.copyTo(this) } val jsonString = _String_(contentCopy.readRemaining()._readBytes_()) Do you know any working solution? Thanks.
a

Aleksei Tirman [JB]

01/23/2023, 9:52 PM
Could you please describe the problem that you’re trying to solve?
1
l

Lubomir Pisk

01/24/2023, 10:40 AM
I have RefreshTokenInterceptor and inside is this check: // 2FA (too returns response code 401) if (twoFactorRepository.isTwoFactor(call.response)) { // return and dont refresh token return call } else { //refresh token } And this is implementation of isTwoFactor: val apiResponse: ApiResponse? = try { // because content can be read only once val contentCopy = _ByteChannel_().apply { response.content.copyTo(this) } val jsonString = _String_(contentCopy.readRemaining()._readBytes_()) json._decodeFromString_(jsonString) } catch (e: Exception) { null } return apiResponse?.errorCode?._equals_(ApiResponse.TWO_FACTOR_ERROR, true) == true Is it clear?
a

Aleksei Tirman [JB]

01/24/2023, 1:29 PM
Could you please explain what is the
RefreshTokenInterceptor
?
l

Lubomir Pisk

01/24/2023, 1:31 PM
Its implementation of HttpSendInterceptor.
class RefreshTokenInterceptor( private val twoFactorRepository: TwoFactoryRepository ) : HttpSendInterceptor { override suspend fun invoke(sender: Sender, request: HttpRequestBuilder): HttpClientCall { val call = sender.execute(request) if(call.response.status.value == 401){ // 2FA (too returns response code 401) if (twoFactorRepository.isTwoFactor(call.response)) { // return and dont refresh token return call } else { //refresh token } } } } class TwoFactorRepository { fun isTwoFactory(reponse: HttpResponse) : Boolean{ val apiResponse: ApiResponse? = try { // because content can be read only once val contentCopy = _ByteChannel_().apply { response.content.copyTo(this) } val jsonString = _String_(contentCopy.readRemaining()._readBytes_()) json._decodeFromString_(jsonString) } catch (e: Exception) { null } return apiResponse?.errorCode?._equals_(ApiResponse.TWO_FACTOR_ERROR, true) == true } }
Is it clear?
a

Aleksei Tirman [JB]

01/25/2023, 7:43 AM
You can read a response body into a byte array and use it as a source for
ByteReadChannel
so the other parts of your application could read the body once more.
Copy code
val client = HttpClient(CIO)

client.plugin(HttpSend).intercept { request ->
    val call = execute(request)
    val body = call.response.content
    val bytes = body.readRemaining().readBytes()

    // Manipulate bytes here

    HttpClientCall(
        client,
        request.build(),
        HttpResponseData(
            statusCode = call.response.status,
            requestTime = call.response.requestTime,
            headers = call.response.headers,
            version = call.response.version,
            body = ByteReadChannel(bytes),
            callContext = call.response.coroutineContext
        )
    )
}

val r = client.get("<https://httpbin.org/get>")
println(r.bodyAsText())
50 Views