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

Flutter Dio拦截器优化:10个同步请求401仅触发一次处理方案

解决Flutter Dio拦截器多同步请求401重复触发问题

核心思路是通过一个状态标记控制401处理逻辑的执行时机,同时利用Completer让后续请求同步等待处理结果,避免重复触发相同逻辑。以下是具体实现方案:

完整拦截器代码

import 'dart:async';
import 'package:dio/dio.dart';

class AuthInterceptor extends Interceptor {
  // 标记是否正在处理401逻辑,避免重复触发
  bool _isHandlingUnauthorized = false;
  // 用于同步后续请求的等待状态
  Completer<void>? _authCompleter;

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    if (err.response?.statusCode == 401) {
      if (!_isHandlingUnauthorized) {
        _isHandlingUnauthorized = true;
        _authCompleter = Completer<void>();

        try {
          // 执行你的401核心处理逻辑:比如跳登录页、刷新Token
          await _processUnauthorized();
          _authCompleter?.complete();
        } catch (e) {
          _authCompleter?.completeError(e);
        } finally {
          _isHandlingUnauthorized = false;
          _authCompleter = null;
        }
      }

      // 等待401处理完成,可选:处理完成后重试原请求
      try {
        await _authCompleter?.future;
        // 如果刷新了Token,更新请求头并重试
        final updatedOptions = _updateRequestToken(err.requestOptions);
        final response = await Dio().fetch(updatedOptions);
        handler.resolve(response);
      } catch (e) {
        handler.reject(err);
      }
      return;
    }

    // 非401错误直接传递
    handler.reject(err);
  }

  // 自定义401处理逻辑,根据业务需求实现
  Future<void> _processUnauthorized() async {
    // 示例:跳转到登录页面(需确保上下文可用,可使用全局导航键)
    // GlobalNavigatorKey.navigatorKey.currentState?.pushReplacementNamed('/login');
    
    // 或刷新Token逻辑:
    // await AuthService.instance.refreshAccessToken();
  }

  // 更新请求头中的Token(如果是刷新Token场景)
  RequestOptions _updateRequestToken(RequestOptions options) {
    final newToken = AuthService.instance.currentToken;
    options.headers['Authorization'] = 'Bearer $newToken';
    return options;
  }
}

简化版(无需重试请求)

如果业务只需要避免重复触发401处理(比如仅跳一次登录页),可以去掉重试逻辑:

@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
  if (err.response?.statusCode == 401) {
    if (!_isHandlingUnauthorized) {
      _isHandlingUnauthorized = true;
      try {
        await _processUnauthorized();
      } finally {
        _isHandlingUnauthorized = false;
      }
    }
    // 后续401请求直接拒绝,不重复执行处理逻辑
    handler.reject(err);
    return;
  }
  handler.reject(err);
}

关键注意点

  • 确保_isHandlingUnauthorized和_authCompleter是拦截器实例的成员变量,若使用全局单例拦截器可直接生效;若为多实例,需将状态移至全局状态管理(如Provider、GetX)中。
  • 跳转登录页时,建议使用全局导航键获取上下文,避免拦截器中无法直接获取BuildContext的问题。
  • 若选择重试请求,需确保新Token已正确更新到请求头,避免再次返回401。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:25:12