You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:15:36