You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 05:57:17