Retrofit中OkHttp刷新Token无响应

问题描述 投票:0回答:1

我在使用 Retrofit 和 OkHttp 的 Android 应用程序中面临令牌刷新机制的问题。以下代码旨在拦截 API 请求,将访问令牌添加到请求标头,并在收到 401 Unauthorized 响应时刷新令牌。但是,刷新令牌请求似乎未按预期运行。

class TokenInterceptor(private val context: Context) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        val accessToken = PreferenceUtil(context).getAccessToken()
        Log.d("ApiClient", "Current token: $accessToken")

        // Add access token to header if it exists
        val requestWithToken = if (accessToken != null) {
            originalRequest.newBuilder()
                .header("Authorization", "Bearer $accessToken")
                .build()
        } else {
            originalRequest
        }

        // Send request
        var originalResponse = chain.proceed(requestWithToken)

        if (originalResponse.code == 401) {
            // Refresh token request
            Log.e("ApiClient", "Token expired error, ${originalResponse.code}")

            val refreshToken = PreferenceUtil(context).getRefreshToken()
            Log.d("ApiClient", "Refresh token: $refreshToken")

            if (refreshToken != null) {
                Log.d("ApiClient", "Refresh token exists!")

                // Asynchronous task to request a new access token
                val newAccessToken = runBlocking {
                    reissueToken(refreshToken)
                    Log.d("ApiClient", "Why is this not working?")
                }

                newAccessToken?.let {
                    Log.d("ApiClient", "Replacing with new refresh token!")

                    val newRequest = originalRequest.newBuilder()
                        .header("Authorization", "Bearer $it")
                        .build()

                    originalResponse = chain.proceed(newRequest)
                }
            }
        }

        return originalResponse
    }

    private suspend fun reissueToken(refreshToken: String): String? {
        return withContext(Dispatchers.IO) {
            val apiService = ApiClient.getInstance(context).create(LogInService::class.java)
            val response = apiService.reissueToken(refreshToken)
            Log.d("ApiClient", "Receiving new response: ${response}")

            if (response.isSuccessful) {
                Log.d("ApiClient", "Response successful")

                response.body()?.let { tokenResponse ->
                    Log.d("ApiClient", "Token successfully renewed")
                    PreferenceUtil(context).setAccessToken(tokenResponse.accessToken)
                    PreferenceUtil(context).setRefreshToken(tokenResponse.refreshToken)
                    return@withContext tokenResponse.accessToken
                }
            } else {
                Log.d("ApiClient", "Response failed...")
                null
            }
        }
    }
}

这是我的代码的相关部分:

  1. ApiClient:使用OkHttpClient初始化Retrofit并添加TokenInterceptor。
  2. TokenInterceptor:拦截请求并检查访问令牌。如果它收到 401 响应,它会尝试刷新令牌。

日志:

"Current token: $accessToken"
"Token expired error, 401"
"Refresh token: $refreshToken"
"Refresh token exists!"
android flutter kotlin retrofit okhttp
1个回答
0
投票

您使用了太多线程。尽量避免

withContext(Dispatchers.IO)
Dispatchers.IO
对于网络调用是正确的,但
reissueToken
函数处于runblocking状态,由于runblocking中的上下文不匹配,可能无法正确切换到IO线程。

© www.soinside.com 2019 - 2024. All rights reserved.