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

如何在RetryPolicy拦截器中传递BuildContext处理401重定向

解决http_interceptor中无法传递BuildContext的问题

方案1:使用全局导航键(GlobalKey)

这是最常用的解决方案,无需在拦截器中传递BuildContext,通过全局键直接控制页面导航。

步骤实现

  1. 在全局范围定义导航键
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
  1. 在MaterialApp中配置该导航键
MaterialApp(
  navigatorKey: navigatorKey,
  // 其他页面路由、主题等配置...
)
  1. 修改refreshToken方法,移除BuildContext参数,改用全局导航键处理跳转
class AuthedApiClient {
  http.Client client = InterceptedClient.build(
    interceptors: [AuthorizationInterceptor()],
    retryPolicy: ExpiredTokenRetryPolicy(),
    requestTimeout: const Duration(seconds: 10),
  );

  static Future<void> refreshToken() async {
    LoginService loginService = LoginService();
    try {
      await loginService.refreshLogin(); // 必须加await,确保令牌刷新完成后再重试请求
    } catch (e) {
      if (e is RefreshTokenException) {
        Fluttertoast.showToast(
          msg: e.message,
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.BOTTOM,
          timeInSecForIosWeb: 1,
          textColor: Colors.black,
          backgroundColor: ThemeColors.errorToastMessage,
          fontSize: 12.0,
        );
      }
      // 通过全局导航键跳转登录页
      navigatorKey.currentState?.pushReplacementNamed('/');
    }
  }
}
  1. 重试策略中直接调用无参数的refreshToken
class ExpiredTokenRetryPolicy extends RetryPolicy {
  @override
  Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async {
    if (response.statusCode == 401) {
      await AuthedApiClient.refreshToken();
      return true;
    }
    return false;
  }
}

方案2:将导航键注入到重试策略中

如果不想依赖全局变量,可以在创建重试策略时传入导航键,保持代码封装性。

步骤实现

  1. 修改重试策略类,添加导航键属性
class ExpiredTokenRetryPolicy extends RetryPolicy {
  final GlobalKey<NavigatorState> navigatorKey;

  ExpiredTokenRetryPolicy({required this.navigatorKey});

  @override
  Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async {
    if (response.statusCode == 401) {
      await AuthedApiClient.refreshToken(navigatorKey);
      return true;
    }
    return false;
  }
}
  1. 调整refreshToken方法,接收导航键参数
class AuthedApiClient {
  static Future<void> refreshToken(GlobalKey<NavigatorState> navigatorKey) async {
    LoginService loginService = LoginService();
    try {
      await loginService.refreshLogin();
    } catch (e) {
      if (e is RefreshTokenException) {
        Fluttertoast.showToast(
          msg: e.message,
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.BOTTOM,
          timeInSecForIosWeb: 1,
          textColor: Colors.black,
          backgroundColor: ThemeColors.errorToastMessage,
          fontSize: 12.0,
        );
      }
      navigatorKey.currentState?.pushReplacementNamed('/');
    }
  }

  // 创建Client时传入带导航键的重试策略
  http.Client client = InterceptedClient.build(
    interceptors: [AuthorizationInterceptor()],
    retryPolicy: ExpiredTokenRetryPolicy(navigatorKey: navigatorKey),
    requestTimeout: const Duration(seconds: 10),
  );
}

关键注意事项

  • 原代码中loginService.refreshLogin()未加await,会导致未完成令牌刷新就重试请求,必须添加await确保令牌更新后再执行重试逻辑。
  • 使用全局导航键时,需确保MaterialApp已完成初始化,否则currentState可能为null。

内容的提问来源于stack exchange,提问作者rafaelpadu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:06:35