Skip to content

网络请求

概述

本文档详细介绍了FluCli项目模板中的网络请求框架,基于Dio和hzy_normal_network库实现,提供了完整的HTTP请求、缓存管理和错误处理解决方案。

网络架构概述

核心组件

  • HTTP配置管理:环境切换、域名配置
  • 网络请求封装:统一的请求接口
  • 缓存策略:基于Dio Cache Interceptor的缓存管理
  • 错误处理:统一的错误处理机制
  • 拦截器支持:请求/响应拦截器

技术栈

组件技术说明
HTTP客户端Dio强大的HTTP客户端
网络框架hzy_normal_network封装的网络请求框架
缓存管理dio_cache_interceptorHTTP缓存拦截器
本地存储Hive轻量级数据库

HTTP配置管理

环境配置

文件定义了完整的HTTP配置:
dart
// 环境枚举
enum HttpEnvironEnmu {
  debug,    // 开发环境
  release,  // 发布环境
}

// 域名枚举
enum HttpBaseUrlEnum {
  normalUrl,  // 默认域名
  otherUrl,   // 其他域名
}

class HttpNormalConfig {
  // 当前环境配置
  static const HttpEnvironEnmu environ = HttpEnvironEnmu.release;
  
  // 获取完整URL
  static String conFigNetWorkPath({
    required String path,
    HttpBaseUrlEnum urlEnum = HttpBaseUrlEnum.normalUrl,
    HttpEnvironEnmu environEnmu = HttpNormalConfig.environ,
  }) {
    String baseurl = configbaseUrl(
      urlEnum: urlEnum,
      environEnmu: environ,
    );
    return baseurl + path;
  }
}

域名配置

dart
// 开发环境域名配置
static String configDebugBaseUrl({
  HttpBaseUrlEnum urlEnum = HttpBaseUrlEnum.normalUrl,
}) {
  switch (urlEnum) {
    case HttpBaseUrlEnum.normalUrl:
      return "http://dev.example.com/api";
    case HttpBaseUrlEnum.otherUrl:
      return "http://dev-other.example.com/api";
  }
}

// 生产环境域名配置
static String configReleaseBaseUrl({
  HttpBaseUrlEnum urlEnum = HttpBaseUrlEnum.normalUrl,
}) {
  switch (urlEnum) {
    case HttpBaseUrlEnum.normalUrl:
      return "https://api.example.com";
    case HttpBaseUrlEnum.otherUrl:
      return "https://api-other.example.com";
  }
}

网络请求封装

请求工具类

提供了统一的网络请求接口:
dart
class NetWorkInstance {
  static final NetWorkInstance _instance = NetWorkInstance._internal();
  factory NetWorkInstance() => _instance;
  
  HzyNormalClient? _client;
  
  // 配置网络客户端
  configClient({required HzyNormalHttpConfig config}) {
    _client = HzyNormalClient(normalHttpConfig: config);
  }
  
  // 获取客户端实例
  HzyNormalClient? getClient() {
    if (_client == null) {
      throw Exception("请先配置网络请求");
    }
    return _client;
  }
}

通用请求方法

dart
/// 通用网络请求方法
Future<HzyNormalResponse> request({
  required String path,           // 请求路径
  dynamic data,                   // 请求参数
  Method method = Method.get,     // 请求方式
  bool isShowLoad = true,         // 是否显示加载动画
  bool isUpdateCaChe = true,      // 是否更新缓存
  bool isShowError = true,        // 是否显示错误提示
  bool isShowSuccessToast = false, // 是否显示成功提示
  bool isNeedGlobalParams = false, // 是否需要全局参数
  HzyNormalTransFormer? httpTransformer, // 拦截器
  CachePolicy? policy,            // 缓存策略
  Options? options,               // 请求选项
}) async {
  // 请求实现
}

缓存管理

缓存配置

提供了完整的缓存管理:
dart
class DioCacheTool {
  static late CacheStore _cacheStore;
  static late CacheOptions cacheOptions;
  
  // 初始化缓存存储
  static Future<void> initCacheStore() async {
    final dir = await getApplicationDocumentsDirectory();
    _cacheStore = HiveCacheStore(
      await Hive.openBox(
        "hzy_basic_http_cache",
        path: dir.path,
      ),
    );
  }
  
  // 初始化缓存拦截器
  static DioCacheInterceptor init() {
    cacheOptions = CacheOptions(
      store: _cacheStore,
      policy: CachePolicy.request,
      hitCacheOnErrorExcept: [401, 403],
      maxStale: const Duration(days: 7),
      priority: CachePriority.normal,
      cipher: null,
      keyBuilder: CacheOptions.defaultCacheKeyBuilder,
      allowPostMethod: false,
    );
    
    return DioCacheInterceptor(options: cacheOptions);
  }
}

缓存策略

策略说明适用场景
forceCache强制缓存,保存所有成功的GET请求静态数据
refreshForceCache刷新强制缓存需要最新数据但允许缓存
noCache不使用缓存实时数据
refresh刷新请求,忽略缓存下拉刷新
request优先使用缓存,过期时请求新数据一般数据

缓存操作

dart
// 获取缓存响应
static Future<CacheResponse?> getHttpCacheResponse({
  required String url,
  required String method,
  Map<String, dynamic>? queryParameters,
}) async {
  // 实现缓存获取逻辑
}

// 清除所有HTTP缓存
static clearHttpCache() async {
  await _cacheStore.clean();
}

// 清除指定URL的缓存
static clearUrlHttpCache({required String url}) async {
  await _cacheStore.delete(url);
}

API接口实现

API类设计

展示了标准的API接口实现:
dart
class EgApis {
  /// 加载列表数据
  Future<dynamic> loadListData({
    int page = 1,
    int? lastPostId,
    bool isShowLoad = false,
  }) async {
    Map<String, dynamic> data = {
      "page": page,
      "type": "loadmore",
    };
    
    if (lastPostId != null) {
      data["post_id"] = lastPostId;
    }
    
    return await request(
      path: "/tc/list",
      data: data,
      isShowLoad: isShowLoad,
      isShowError: false,
      method: Method.get,
      policy: isShowLoad 
          ? CachePolicy.refreshForceCache 
          : CachePolicy.forceCache,
      options: Options(
        sendTimeout: lastPostId != null 
            ? const Duration(milliseconds: 3000) 
            : null,
      ),
    );
  }
}

API使用示例

dart
class DemoController extends BaseGetXController {
  final EgApis _api = EgApis();
  
  @override
  Future<void> getNetWorkData({int? type, Map<String, dynamic>? info}) async {
    try {
      final response = await _api.loadListData(
        page: currentPage.value,
        isShowLoad: type == 3,
      );
      
      if (response.isSuccess) {
        // 处理成功响应
        handleSuccessResponse(response.data);
      } else {
        // 处理错误响应
        handleErrorResponse(response.error);
      }
    } catch (e) {
      // 处理异常
      handleException(e);
    }
  }
}

网络初始化

应用启动配置

中进行网络初始化:

dart
class LaunchConfig {
  static Future<void> init() async {
    // 初始化缓存存储
    await DioCacheTool.initCacheStore();
    
    // 初始化网络配置
    await initNetWork();
  }
  
  static Future<void> initNetWork() async {
    // 配置响应转换器
    HzyNormalDefaultTransFormer.getInstance().setHttpConfig(
      config: HzyNormalHttpResponeConfig(
        successCode: 200,
        successField: "code",
        msgField: "msg",
        dataField: "data",
      ),
    );
    
    // 配置网络客户端
    NetWorkInstance().configClient(
      config: HzyNormalHttpConfig(
        baseUrl: HttpNormalConfig.configbaseUrl(),
        connectTimeout: const Duration(milliseconds: 30000),
        receiveTimeout: const Duration(milliseconds: 30000),
        interceptors: [
          DioCacheTool.init(), // 添加缓存拦截器
        ],
      ),
    );
  }
}

错误处理

统一错误处理

dart
// 在请求方法中的错误处理
if (!res.isSuccess) {
  if (isShowError) {
    EasyLoading.showError(
      res.error?.msg ?? "网络请求失败",
    );
  }
  
  return HzyNormalResponse.fail(
    msg: res.error?.msg ?? "NetWork Fail",
    code: res.error?.code ?? -1,
  );
}

错误类型

错误类型处理方式说明
网络超时自动重试连接超时或读取超时
服务器错误显示错误信息5xx状态码
客户端错误显示错误信息4xx状态码
解析错误显示通用错误JSON解析失败

最佳实践

开发建议

  1. 环境配置

    • 开发和生产环境使用不同的域名
    • 通过环境变量控制当前环境
    • 支持多域名切换
  2. 缓存策略

    • 静态数据使用强制缓存
    • 动态数据使用请求缓存
    • 实时数据不使用缓存
  3. 错误处理

    • 统一错误处理机制
    • 友好的错误提示
    • 适当的重试策略

性能优化

  1. 请求优化

    • 合理设置超时时间
    • 使用连接池复用连接
    • 压缩请求和响应数据
  2. 缓存优化

    • 设置合理的缓存过期时间
    • 定期清理过期缓存
    • 控制缓存大小
  3. 内存管理

    • 及时释放大文件下载的内存
    • 避免内存泄漏
    • 合理使用单例模式

安全考虑

  1. HTTPS使用

    • 生产环境强制使用HTTPS
    • 证书验证
    • 防止中间人攻击
  2. 数据安全

    • 敏感数据加密传输
    • API密钥安全存储
    • 请求签名验证

相关链接

根据 MIT 许可发布。