Retrofit:如何确保发起网络请求前等待Firebase Token获取完成?
解决方案
1. 封装Firebase Token的异步获取逻辑
先把Firebase Token的回调转换成可等待的异步操作,避免回调嵌套:
Kotlin 协程实现
class FirebaseTokenManager { suspend fun getValidToken(): String { return suspendCancellableCoroutine { continuation -> FirebaseMessaging.getInstance().token.addOnCompleteListener { task -> if (task.isSuccessful) { task.result?.let { token -> continuation.resume(token) } ?: continuation.resumeWithException(IllegalStateException("Token为空")) } else { continuation.resumeWithException(task.exception ?: IllegalStateException("获取Token失败")) } } } } }
Java CompletableFuture实现
public class FirebaseTokenManager { public CompletableFuture<String> getValidToken() { CompletableFuture<String> future = new CompletableFuture<>(); FirebaseMessaging.getInstance().getToken() .addOnCompleteListener(task -> { if (task.isSuccessful()) { String token = task.getResult(); if (token != null) { future.complete(token); } else { future.completeExceptionally(new IllegalStateException("Token为空")); } } else { future.completeExceptionally(task.getException() != null ? task.getException() : new IllegalStateException("获取Token失败")); } }); return future; } }
2. 确保网络请求在Token获取完成后执行
Kotlin 协程场景
在Repository或ViewModel中先获取Token,再发起请求:
class ApiRepository(private val tokenManager: FirebaseTokenManager, private val apiService: ApiService) { suspend fun fetchData(): Result<DataModel> { return try { val token = tokenManager.getValidToken() val response = apiService.fetchData() if (response.isSuccessful) { Result.success(response.body()!!) } else { Result.failure(IOException("请求失败: ${response.code()}")) } } catch (e: Exception) { Result.failure(e) } } }
Java CompletableFuture场景
public class ApiRepository { private final FirebaseTokenManager tokenManager; private final ApiService apiService; public ApiRepository(FirebaseTokenManager tokenManager, ApiService apiService) { this.tokenManager = tokenManager; this.apiService = apiService; } public CompletableFuture<DataModel> fetchData() { return tokenManager.getValidToken() .thenCompose(token -> apiService.fetchData()) .thenApply(response -> { if (response.isSuccessful()) { return response.body(); } else { throw new IOException("请求失败: " + response.code()); } }); } }
3. 用Retrofit拦截器自动添加Token到请求头
通过拦截器统一处理请求头,无需每次手动传入Token:
Kotlin 实现
class AuthInterceptor(private val tokenManager: FirebaseTokenManager) : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): Response { val token = tokenManager.getValidToken() val request = chain.request() .newBuilder() .addHeader("Authorization", "Bearer $token") .build() return chain.proceed(request) } } // 构建Retrofit实例 val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .client(OkHttpClient.Builder() .addInterceptor(AuthInterceptor(tokenManager)) .build()) .build()
Java 实现
public class AuthInterceptor implements Interceptor { private final FirebaseTokenManager tokenManager; public AuthInterceptor(FirebaseTokenManager tokenManager) { this.tokenManager = tokenManager; } @Override public Response intercept(Chain chain) throws IOException { String token = tokenManager.getValidToken().join(); Request request = chain.request() .newBuilder() .addHeader("Authorization", "Bearer " + token) .build(); return chain.proceed(request); } } // 构建Retrofit实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(CompletableFutureCallAdapterFactory.create()) .client(new OkHttpClient.Builder() .addInterceptor(new AuthInterceptor(tokenManager)) .build()) .build();
4. 处理Token过期重试逻辑
如果请求返回401(Token过期),可在拦截器中重新获取Token并重试:
override suspend fun intercept(chain: Interceptor.Chain): Response { val token = tokenManager.getValidToken() val request = chain.request().newBuilder() .addHeader("Authorization", "Bearer $token") .build() val response = chain.proceed(request) if (response.code() == 401) { val newToken = tokenManager.getValidToken() val newRequest = request.newBuilder() .header("Authorization", "Bearer $newToken") .build() return chain.proceed(newRequest) } return response }
内容的提问来源于stack exchange,提问作者Oscar Berggren
相关产品推荐
相关产品推荐

