android - How call Authenticator.authenticate with custom respond in okhttp? - Stack Overflow

时间: 2025-01-06 admin 业界

Request process

request:

url:http://host/test
method: post
body:{"token":"AAA"}

if token is invalid respond:

{"code":401,"msg":"unauth"}

Now,I hope Authenticator.authenticate can be called then retry request:

url:http://host/test
method: post
body:{"token":"BBB"}

if token is invalid respond:

{"code":200,"msg":"ok"}

Kotlin Code

OkHttpClient.Builder()
    .writeTimeout(10, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.SECONDS)
    .connectTimeout(10, TimeUnit.SECONDS)
    .callTimeout(10, TimeUnit.SECONDS)
    .addInterceptor {
        val request = it.request()
        Log.d(Tags.HTTP, "address: ${request.url}")
        val response = it.proceed(request)
        response.body?.let { body ->
            val bodyString = body.string()
            if (bodyString.decodeJson<BaseResponse>().code == 401) {
                response.newBuilder().code(401).message("Not Authorized").build()
            } else {
                response.newBuilder().body(bodyString.toResponseBody("text/plain".toMediaType())).build()
            }
        } ?: response
    }
    .authenticator(object : Authenticator {
        override fun authenticate(route: Route?, response: Response): Request? {
            Log.d(TAG, "start retry auth")
            return response.request.newBuilder().method(request.method,"{\"token\":\"BBB\"".toRequestBody("application/json".toMediaType()))
        }
    })
    .build()

Why I send invalid token,Authenticator.authenticate not be called.

Request process

request:

url:http://host/test
method: post
body:{"token":"AAA"}

if token is invalid respond:

{"code":401,"msg":"unauth"}

Now,I hope Authenticator.authenticate can be called then retry request:

url:http://host/test
method: post
body:{"token":"BBB"}

if token is invalid respond:

{"code":200,"msg":"ok"}

Kotlin Code

OkHttpClient.Builder()
    .writeTimeout(10, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.SECONDS)
    .connectTimeout(10, TimeUnit.SECONDS)
    .callTimeout(10, TimeUnit.SECONDS)
    .addInterceptor {
        val request = it.request()
        Log.d(Tags.HTTP, "address: ${request.url}")
        val response = it.proceed(request)
        response.body?.let { body ->
            val bodyString = body.string()
            if (bodyString.decodeJson<BaseResponse>().code == 401) {
                response.newBuilder().code(401).message("Not Authorized").build()
            } else {
                response.newBuilder().body(bodyString.toResponseBody("text/plain".toMediaType())).build()
            }
        } ?: response
    }
    .authenticator(object : Authenticator {
        override fun authenticate(route: Route?, response: Response): Request? {
            Log.d(TAG, "start retry auth")
            return response.request.newBuilder().method(request.method,"{\"token\":\"BBB\"".toRequestBody("application/json".toMediaType()))
        }
    })
    .build()

Why I send invalid token,Authenticator.authenticate not be called.

Share Improve this question asked yesterday 卡尔斯路西法卡尔斯路西法 1038 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

I resolve the question by only Interceptor,but it is not best answer,so i watting a better answer.

OkHttpClient.Builder().addInterceptor {
        val request = it.request()
        val response = it.proceed(request)
        response.body?.let { body ->
            val bodyString = body.string()
            // “code" in body
            if (bodyString.decodeJson<BaseResponse>().code == 401) {
                val copyRespond = response.newBuilder().build()
                // not call authenticate by okhttp
                // when you need just call it
                // but it not try more times
                val authorizedRequest = authenticate(copyRespond)
                if (authorizedRequest != null) {
                    it.proceed(authorizedRequest)
                } else {
                    copyRespond
                }

            } else {
                response.newBuilder().body(bodyString.toResponseBody("text/plain".toMediaType())).build()
            }
        } ?: response
    }
    .build()