有这样一个拦截器:
class AuthToken(context: Context) : Interceptor {
var cont = context
override fun intercept(chain: Interceptor.Chain): Response {
val sp = cont.getSharedPreferences("app_data", 0)
val originalRequest:Request? = (if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
updateToken(chain)
null
} else {
chain.request()
.newBuilder()
.header("Content-type:", "application/json")
.header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
.build()
})
if (originalRequest!=null){
val response = chain.proceed(originalRequest)
when (response.code) {
401 -> {
updateToken(chain)
}
500 -> {
Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
}
}
return response
}else chain.proceed(originalRequest)
}
private fun updateToken(request: Interceptor.Chain) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val dispatcher = Dispatcher()
dispatcher.maxRequests = 1
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(100, TimeUnit.SECONDS)
.dispatcher(dispatcher)
.readTimeout(100, TimeUnit.SECONDS).build()
client.dispatcher.cancelAll()
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retrofit.create(APIService::class.java)
api.getNewToken(ReqAccessToken(cont.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!)).enqueue(object : Callback<ResNewTokens> {
override fun onResponse(call: Call<ResNewTokens>, response: retrofit2.Response<ResNewTokens>) {
if (response.isSuccessful) {
val editor = cont.getSharedPreferences("app_data", 0).edit()
editor.putString("access_token", Objects.requireNonNull<ResNewTokens>(response.body()).access_token).apply()
editor.putString("refresh_token", Objects.requireNonNull<ResNewTokens>(response.body()).refresh_token).apply()
editor.putLong("expires_in", response.body()!!.expires_in!!).apply()
makeNewCall(request)
} else {
when (response.code()) {
401 -> {
Singleton.logOut(cont)
}
500 -> {
Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
}
}
}
}
override fun onFailure(call: Call<ResNewTokens>, t: Throwable) {
}
})
}
private fun makeNewCall(req: Interceptor.Chain): Request {
return req.request()
.newBuilder()
.header("Content-type:", "application/json")
.header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
.build()
}
}
问题出在以下几行:
if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
updateToken(chain)
null
}
我要解决的问题的本质是删除带有腐烂令牌的额外请求,该令牌肯定会返回 401 错误。为此,我将所有内容都包装在了 if 中,但无法正常实现,因为函数intercept必须以任何方式返回Response,而在这种情况下不会这样做。想使那个 null 被发送,但结果是歪曲的。您需要以某种方式取消为消息计划的请求,或者以某种方式解决此问题,但我不知道具体如何:(
更新:
以下是目前的成果:
override fun intercept(chain: Interceptor.Chain): Response {
val sp = cont.getSharedPreferences("app_data", 0)
val originalRequest = if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val dispatcher = Dispatcher()
dispatcher.maxRequests = 1
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(100, TimeUnit.SECONDS)
.dispatcher(dispatcher)
.readTimeout(100, TimeUnit.SECONDS).build()
client.dispatcher.cancelAll()
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api = retrofit.create(APIService::class.java)
synchronized(this) {
when {
api.getNewToken(ReqAccessToken(cont.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!)).execute().isSuccessful -> {
val responseBody = api.getNewToken(ReqAccessToken(cont.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!)).execute().body()
val editor = cont.getSharedPreferences("app_data", 0).edit()
editor.putString("access_token", Objects.requireNonNull<ResNewTokens>(responseBody).access_token).apply()
editor.putString("refresh_token", Objects.requireNonNull<ResNewTokens>(responseBody).refresh_token).apply()
editor.putLong("expires_in", responseBody!!.expires_in!!).apply()
chain.request()
.newBuilder()
.header("Content-type:", "application/json")
.header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
.build()
}
else->{
}
}
}
} else {
chain.request()
.newBuilder()
.header("Content-type:", "application/json")
.header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
.build()
}
val response = chain.proceed(originalRequest)
when (response.code) {
401 -> {
//updateToken(chain)
}
500 -> {
Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
}
}
return response
}
并val response = chain.proceed(originalRequest)说他们正在等待请求。然后我尝试在 if 中规定请求,但据我所知,它不可见。
你应该得到这样的结果: