Dart中调用RefreshToken获新AccessToken后,如何通过拦截器重试API请求?
解决Dart中刷新Token后重新发起原请求的问题
要实现刷新Token后自动重试原请求,核心是确保重试时使用最新的AccessToken,同时避免重复触发Token刷新。以下是具体的优化方案:
1. 统一Token管理
用单例类存储和刷新Token,确保所有请求共享最新的Token实例:
import 'dart:convert'; import 'package:http/http.dart' as http; class FitbitAuth { static final FitbitAuth instance = FitbitAuth._(); FitbitAuth._(); String? accessToken; String? refreshToken; // 实现RefreshToken接口调用逻辑 Future<void> refreshAccessToken() async { final response = await http.post( Uri.parse('https://api.fitbit.com/oauth2/token'), headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: { 'grant_type': 'refresh_token', 'refresh_token': refreshToken!, 'client_id': 'YOUR_CLIENT_ID', // 替换为你的Fitbit Client ID // 若需要client_secret,在此添加对应的参数 }, ); if (response.statusCode != 200) { throw Exception('刷新Token失败: ${response.body}'); } final tokenData = jsonDecode(response.body); accessToken = tokenData['access_token']; refreshToken = tokenData['refresh_token']; } }
2. 动态注入最新Token到请求头
修改拦截器,每次发起请求时从单例类获取最新AccessToken,确保重试请求也能拿到新Token:
import 'package:dio/dio.dart'; class FitbitApiInterceptor extends Interceptor { @override Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async { final latestToken = FitbitAuth.instance.accessToken; if (latestToken != null) { options.headers['Authorization'] = 'Bearer $latestToken'; } super.onRequest(options, handler); } }
3. 优化重试策略,避免重复刷新
给RetryPolicy加锁,防止多个并发401请求同时触发Token刷新;同时限制重试次数,避免无限循环:
import 'package:dio/dio.dart'; import 'package:synchronized/synchronized.dart'; class ExpiredTokenRetryPolicy extends RetryPolicy { final _refreshLock = Lock(); @override Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async { if (response.statusCode == 401) { try { // 加锁确保同一时间只有一个请求触发Token刷新 await _refreshLock.synchronized(() async { await FitbitAuth.instance.refreshAccessToken(); }); return true; // 允许重试原请求 } catch (e) { print('Token刷新失败: $e'); return false; // 刷新失败则终止重试 } } return false; } // 限制最多重试1次,避免刷新后仍401导致无限重试 @override int get maxRetryAttempts => 1; }
4. 构建客户端
最后构建带拦截器和重试策略的客户端:
import 'package:dio/dio.dart'; import 'package:dio_interceptor/dio_interceptor.dart'; Client client = InterceptedClient.build( interceptors: [FitbitApiInterceptor()], retryPolicy: ExpiredTokenRetryPolicy(), );
关键说明
- 动态Token注入:拦截器每次请求都重新获取最新Token,确保重试请求使用的是刷新后的新Token
- 避免重复刷新:通过锁机制防止多个并发的401请求同时调用RefreshToken接口
- 失败处理:Token刷新失败时返回
false,终止重试流程,避免无效请求
内容的提问来源于stack exchange,提问作者F sam
相关产品推荐
相关产品推荐

