我在使用 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
}
}
}
}
这是我的代码的相关部分:
日志:
"Current token: $accessToken"
"Token expired error, 401"
"Refresh token: $refreshToken"
"Refresh token exists!"
您使用了太多线程。尽量避免
withContext(Dispatchers.IO)
。
Dispatchers.IO
对于网络调用是正确的,但reissueToken
函数处于runblocking状态,由于runblocking中的上下文不匹配,可能无法正确切换到IO线程。