Flutter中Dio请求因设备断网未完成时如何自动后台重试?
Dio断网后自动后台重试GET请求方案
要实现断网失败的GET请求在网络恢复后自动后台重试,核心要做三件事:监听网络状态变化、缓存失败请求、网络恢复时触发重试。以下是具体实现步骤:
1. 添加依赖
在pubspec.yaml中引入所需包:
dependencies: dio: ^5.4.0+1 connectivity_plus: ^5.0.1 shared_preferences: ^2.2.2
2. 实现网络状态监听
创建工具类监听网络状态,当网络从断开恢复时触发回调:
import 'package:connectivity_plus/connectivity_plus.dart'; class NetworkMonitor { final Connectivity _connectivity = Connectivity(); bool _isConnected = false; // 初始化监听 Future<void> init({required Function() onNetworkRestored}) async { var result = await _connectivity.checkConnectivity(); _isConnected = result != ConnectivityResult.none; _connectivity.onConnectivityChanged.listen((result) { final wasConnected = _isConnected; _isConnected = result != ConnectivityResult.none; // 网络从断开变为连接时触发重试回调 if (!wasConnected && _isConnected) { onNetworkRestored(); } }); } }
3. 实现Dio拦截器缓存失败请求
创建拦截器,捕获网络错误并缓存请求信息,同时处理重试逻辑:
import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; class RetryInterceptor extends Interceptor { final Dio _dio; final SharedPreferences _prefs; static const _cacheKey = 'failed_get_requests'; RetryInterceptor(this._dio, this._prefs); @override void onError(DioException err, ErrorInterceptorHandler handler) async { // 判定是否为网络类错误 if (err.type == DioExceptionType.connectionError || err.type == DioExceptionType.sendTimeout || err.type == DioExceptionType.receiveTimeout) { // 仅缓存GET请求 if (err.requestOptions.method == 'GET') { await _cacheFailedRequest(err.requestOptions); } } super.onError(err, handler); } // 缓存失败的请求信息 Future<void> _cacheFailedRequest(RequestOptions options) async { List<Map<String, dynamic>> cachedRequests = await _getCachedRequests(); // 去重,避免重复缓存同一请求 bool exists = cachedRequests.any((req) => req['url'] == options.uri.toString() && jsonEncode(req['queryParameters']) == jsonEncode(options.queryParameters)); if (!exists) { cachedRequests.add({ 'url': options.uri.toString(), 'queryParameters': options.queryParameters, }); await _prefs.setString(_cacheKey, jsonEncode(cachedRequests)); } } // 获取缓存的请求列表 Future<List<Map<String, dynamic>>> _getCachedRequests() async { String? jsonStr = _prefs.getString(_cacheKey); if (jsonStr == null) return []; return List<Map<String, dynamic>>.from(jsonDecode(jsonStr)); } // 重试所有缓存的失败请求 Future<void> retryFailedRequests() async { List<Map<String, dynamic>> cachedRequests = await _getCachedRequests(); if (cachedRequests.isEmpty) return; for (var req in cachedRequests.toList()) { try { await _dio.get( req['url'], queryParameters: req['queryParameters'], ); // 请求成功后从缓存移除 cachedRequests.remove(req); await _prefs.setString(_cacheKey, jsonEncode(cachedRequests)); } catch (e) { // 重试失败,保留缓存等待下次网络恢复 continue; } } } }
4. 整合逻辑初始化
在项目入口或全局初始化处,完成Dio、网络监听和拦截器的整合:
import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() async { // 初始化SharedPreferences final prefs = await SharedPreferences.getInstance(); // 初始化Dio实例 final dio = Dio(); // 创建拦截器并添加到Dio final retryInterceptor = RetryInterceptor(dio, prefs); dio.interceptors.add(retryInterceptor); // 初始化网络监听,绑定重试触发逻辑 final networkMonitor = NetworkMonitor(); networkMonitor.init(onNetworkRestored: () { retryInterceptor.retryFailedRequests(); }); // 后续正常发起GET请求即可 // dio.get('https://api.example.com/data'); }
注意事项
- 可添加重试次数限制,避免无限重试(例如在重试时记录次数,超过阈值则移除缓存)
- 若请求包含签名、时效性参数,需额外处理参数有效性,避免重试时参数失效
- 可根据业务需求扩展缓存的请求信息(如请求头、自定义参数)
内容的提问来源于stack exchange,提问作者An Tran
相关产品推荐
相关产品推荐

