Flutter中使用Bloc实现Token/Refresh Token过期跳转至登出页
全局统一处理Token过期跳转方案
不用在每个Bloc里重复写401监听逻辑,直接通过Dio全局拦截器一次性配置,所有网络请求自动触发过期处理:
1. 配置全局Dio实例+拦截器
先创建全局Dio单例(不要每次请求都new Dio,否则拦截器无法生效),添加错误拦截器捕获401状态码:
// 全局Dio实例,放在你的网络工具类中 final Dio dio = Dio() ..interceptors.add(InterceptorsWrapper( onError: (DioError e, ErrorInterceptorHandler handler) async { // 捕获Token/Refresh Token过期的401状态码 if (e.response?.statusCode == 401) { // 执行登出逻辑:清空本地Token、跳转自定义登出页面 // 用全局NavigatorKey获取上下文(需提前在MaterialApp配置) GlobalNavigatorKey.navigatorKey.currentState?.pushReplacement( MaterialPageRoute(builder: (context) => const CustomLogoutPage()), ); } handler.next(e); // 继续传递错误供上层业务处理(可选) }, )); // 全局NavigatorKey类,用于无上下文跳转 class GlobalNavigatorKey { static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); } // 在MaterialApp中配置全局key MaterialApp( navigatorKey: GlobalNavigatorKey.navigatorKey, // ...其他页面路由配置 )
2. 修改get方法使用全局Dio
替换原来每次new Dio()的写法,改用全局实例确保拦截器生效:
@override Future<Map<String, dynamic>> get(String url) async { final newUrl = baseUrl + url; try { final response = await dio.get( newUrl, options: Options(headers: headersList), ).timeout(duration); final result = _processResponse(response); if (result.runtimeType.toString().toLowerCase() == 'string') { return <String, String>{'key': result as String}; } return result as Map<String, dynamic>; } on SocketException { throw FetchDataException('internetConnection'); } on TimeoutException { throw ApiNotRespondingException('api not found '); } on DioError catch (e) { print(e.toString()); throw _handleError(e); } }
额外优化建议
- 可以在拦截器中先尝试自动刷新Token,刷新失败再跳转登出,提升用户体验
- 添加全局标记变量,防止多次401请求触发重复跳转
内容的提问来源于stack exchange,提问作者moein_keyvanipur
相关产品推荐
相关产品推荐

