Token过期/刷新时仅返回文本错误,如何实现自动登出跳转登录页?
问题:Token过期时未自动跳转登录页
当前问题:用户处于登录状态且Token过期时,应用未自动跳转至登录页,仅返回文本形式的错误,无跳转行为。
相关代码
调用API代码
class UserProvider with ChangeNotifier { late User _user; User get user => _user; set user(User newUser) { _user = newUser; notifyListeners(); } Future<User?> login(String nim, String password) async { String url = Constant.baseURL; try { var body = { 'username': nim, 'password': password, }; var response = await http.post( Uri.parse( '$url/login_mhs', ), body: body, ); if (response.statusCode == 200) { final token = jsonDecode(response.body)['data']['access_token']; await UtilSharedPreferences.setToken(token); print(token); return User.fromJson(jsonDecode(response.body)); } else { return null; } } catch (e) { print(e); throw Exception(); } } }
启动页(SplashScreen)代码
class _SplashScreenState extends State<SplashScreen> { Future<void> toLogin() async { Timer( const Duration(seconds: 3), () async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? token = prefs.getString(Constant.token); // ignore: use_build_context_synchronously Navigator.pushReplacementNamed( context, token != null ? AppRoute.mainRoute : AppRoute.loginRoute, arguments: token, ); }, ); } @override void initState() { super.initState(); toLogin(); } }
错误返回示例

解决方案
1. 全局拦截API请求,处理Token过期
创建HTTP拦截器,统一处理所有请求的响应,识别Token过期状态(通常为401状态码):
// 先定义全局导航键,用于在拦截器中获取上下文 final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); class AuthInterceptor extends Interceptor { @override void onResponse(Response response, ResponseInterceptorHandler handler) { if (response.statusCode == 401) { // 清除本地过期Token UtilSharedPreferences.removeToken(); // 跳转登录页 navigatorKey.currentState?.pushReplacementNamed(AppRoute.loginRoute); } super.onResponse(response, handler); } } // 初始化Dio时挂载拦截器 final dio = Dio()..interceptors.add(AuthInterceptor());
2. 启动页增加Token有效性校验
当前启动页仅判断Token是否存在,未校验是否过期,新增校验逻辑:
Future<void> toLogin() async { Timer( const Duration(seconds: 3), () async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? token = prefs.getString(Constant.token); if (token != null) { // 调用后端校验Token接口 bool isValid = await _checkToken(token); if (!isValid) { await prefs.remove(Constant.token); Navigator.pushReplacementNamed(context, AppRoute.loginRoute); return; } Navigator.pushReplacementNamed(context, AppRoute.mainRoute, arguments: token); } else { Navigator.pushReplacementNamed(context, AppRoute.loginRoute); } }, ); } // 校验Token有效性的方法 Future<bool> _checkToken(String token) async { try { final response = await http.get( Uri.parse('${Constant.baseURL}/validate_token'), headers: {'Authorization': 'Bearer $token'}, ); return response.statusCode == 200; } catch (e) { return false; } }
3. 在状态管理中处理Token过期事件
在UserProvider中新增Token过期处理方法,供页面或请求失败时调用:
class UserProvider with ChangeNotifier { // ...原有代码... void handleTokenExpired() async { await UtilSharedPreferences.removeToken(); notifyListeners(); navigatorKey.currentState?.pushReplacementNamed(AppRoute.loginRoute); } }
内容的提问来源于stack exchange,提问作者Meikisihka
相关产品推荐
相关产品推荐

