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
相关产品推荐
相关产品推荐

