• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Flutter 实现统一处理Token过期后跳转登录页面

武飞扬头像
xhu_ww
帮助1

1 方式一:使用全局GlobalKey

1.1 创建全局GlobalKey

配置路由 并设置 globalNavigatorKey

final GlobalKey<NavigatorState> globalNavigatorKey = GlobalKey();

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 配置路由 并设置 globalNavigatorKey
    return MaterialApp(
      initialRoute: "/",
      navigatorKey: globalNavigatorKey,
      onGenerateRoute: (settings) {
        final routeName = settings.name;
        switch (routeName) {
          case "/":
            return ...
          case "/login":
            return MaterialPageRoute(
              builder: (context) => const LoginPage(),
            );
          case "/tabPage":
            return MaterialPageRoute(builder: (context) => const TabPage());
          default:
            return ...;
        }
      },
    );
  }
}

学新通

1.2 网络请求拦截器中检测到Token过期则跳转页面

此处使用网络请求框架是 dio,添加拦截器,并使用 globalNavigatorKey 跳转登录页面。

// 添加拦截器
final dio = Dio()..interceptors.add(ApiInterceptor());

class ApiInterceptor extends InterceptorsWrapper {
  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    super.onError(err, handler);
    int? statusCode = err.response?.statusCode;
    if (statusCode == 401) {
      // 跳转登录页面并清空栈
      globalNavigatorKey.currentState
          ?.pushNamedAndRemoveUntil('/login', (route) => false);
    }
  }
}

1.3 可能出现的问题

当同时存在多个网络请求时,拦截器中跳转登录页面的操作可能会同时调用几次,出现多次跳转登录页面的情况。

2 方式二:使用事件总线

2.1 创建事件总线

class EventBus {
  //私有构造函数
  EventBus._internal();

  static EventBus? _instance;

  static EventBus get instance => _getInstance();

  static EventBus _getInstance() {
    return _instance ??= EventBus._internal();
  }

  // 存储事件回调方法
  final Map<String, Function> _events = {};

  // 设置事件监听
  void addListener(String eventKey, Function callback) {
    _events[eventKey] = callback;
  }

  // 移除监听
  void removeListener(String eventKey) {
    _events.remove(eventKey);
  }

  // 提交事件
  void commit(String eventKey) {
    _events[eventKey]?.call();
  }
}

class EventKeys {
  static const String logout = "Logout";
}
学新通

2.2 监听登出事件

登录成功后,在主页面设置登出事件监听,事件响应后立即移除监听。

class TabPage extends StatefulWidget {
  const TabPage({Key? key}) : super(key: key);

  @override
  State<TabPage> createState() => _TabPageState();
}

class _TabPageState extends State<TabPage> {
  @override
  void initState() {
    super.initState();
    EventBus.instance.addListener(EventKeys.logout, () {
      // 移除事件监听
      EventBus.instance.removeListener(EventKeys.logout);
      // 跳转登录页面
      Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
    });
  }

  @override
  void dispose() {
    // 移除事件监听
    EventBus.instance.removeListener(EventKeys.logout);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ...
  }
}
学新通

2.3 网络请求拦截器中触发登出事件

final dio = Dio()..interceptors.add(ApiInterceptor());

class ApiInterceptor extends InterceptorsWrapper {
  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    super.onError(err, handler);
    int? statusCode = err.response?.statusCode;
    if (statusCode == 401) {
      // 触发登出事件
      EventBus.instance.commit(EventKeys.logout);
    }
  }
}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbjihc
系列文章
更多 icon
同类精品
更多 icon
继续加载