Flutter Web Navigator 2.0如何解决404返回按钮循环问题
问题表现
当用户处于404页面时点击浏览器返回按钮,URL会变更为最初触发路由错误的地址,页面会再次渲染显示404,形成死循环。
根因分析
navigatorKey被实现为getter,每次调用都会生成新的GlobalKey,Navigator状态无法持久保持,页面弹出逻辑执行异常。setNewRoutePath切换路由时仅设置目标页的标志位,未重置其他页面的状态标志,容易出现多页面标志位同时为true的异常状态。- 触发404时,未将浏览器历史栈中的非法URL替换为404地址,导致历史栈同时存在「非法URL」和「/404」两条记录,点击返回时会回退到非法URL,再次触发404解析形成循环。
onPopPage仅处理了404页面的状态复位,其他页面弹出时对应标志位不会重置,路由状态和实际页面栈不一致。- 首页路由映射不一致:
parseRouteInformation中/对应首页,restoreRouteInformation中首页却映射为/home,导致URL状态错乱。
完整修复步骤
1. 修复navigatorKey初始化
将navigatorKey改为静态初始化,保证全局唯一:
// 替换原有navigatorKey的getter实现 final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>(); @override GlobalKey<NavigatorState>? get navigatorKey => _navigatorKey;
2. 重写setNewRoutePath状态逻辑
每次设置新路由前先重置所有状态为默认值,触发404时使用Router.neglect替换当前历史记录,不新增栈条目:
@override Future<void> setNewRoutePath(PageRoutePath path) async { // 第一步:重置所有路由状态为默认首页状态 isLanding = true; isServices = false; isBrochure = false; isContact = false; isCareers = false; isProductsPage = false; isProductPage = false; productId = null; isGallery = false; isUnknown = false; show404 = false; isPrivacyPolicy = false; // 处理未知路由 if (path.isUnknown) { show404 = true; isLanding = false; // 替换历史记录,不新增栈条目,避免非法URL留在历史栈 Router.neglect(_navigatorKey.currentContext!, () { notifyListeners(); }); return; } // 处理各业务路由 if (path.isServices) { isServices = true; isLanding = false; } if (path.isContact) { isContact = true; isLanding = false; } if (path.isCareers) { isCareers = true; isLanding = false; } if (path.isProductsPage) { isProductsPage = true; isLanding = false; } if (path.isProductPage && path.productId != null) { // 商品ID非法时同样返回404并替换历史记录 if (path.productId! < 0 || path.productId! > product_data.length - 1) { show404 = true; isLanding = false; Router.neglect(_navigatorKey.currentContext!, () { notifyListeners(); }); return; } isProductPage = true; productId = path.productId; isLanding = false; } if (path.isGallery) { isGallery = true; isLanding = false; } if (path.isPrivacyPolicy) { isPrivacyPolicy = true; isLanding = false; } notifyListeners(); }
3. 修复onPopPage状态复位逻辑
页面弹出时同步重置对应页面的标志位,保证路由状态和页面栈一致:
onPopPage: (route, result) { if (!route.didPop(result)) { return false; } final currentPage = route.settings as MaterialPage; // 根据弹出页面的key重置对应状态 switch (currentPage.key) { case ValueKey('404'): show404 = false; break; case ValueKey('service'): isServices = false; break; case ValueKey('brochure'): isBrochure = false; break; case ValueKey('contact-us'): isContact = false; break; case ValueKey('careers'): isCareers = false; break; case ValueKey('products-page'): isProductsPage = false; break; case ValueKey('product-page'): isProductPage = false; productId = null; break; case ValueKey('gallery'): isGallery = false; break; case ValueKey('privacy-policy'): isPrivacyPolicy = false; break; } // 所有子页面弹出后回到首页状态 isLanding = navigatorKey!.currentState!.pages.length == 2; notifyListeners(); return true; }
4. 修复首页路由映射
找到PageRouteInformationParser的restoreRouteInformation方法,修改首页返回的地址,和解析逻辑对齐:
// 原有代码返回/home,改为返回/ return const RouteInformation(location: '/');
修复验证
修改完成后,访问非法URL触发404时,浏览器历史栈不会保留非法地址记录,点击返回按钮会直接回到进入非法地址前的正常页面,404死循环问题解决。
内容的提问来源于stack exchange,提问作者Delwinn
相关产品推荐
相关产品推荐

