一文带你了解 Flutter dio封装

简介: 一文带你了解 Flutter dio封装

封装网络库考虑的几个方面:

  1. 请求参数的封装:将请求所需的参数进行封装,例如 URL、请求头、请求体等。可以定义一个统一的数据结构或模型类来表示请求参数,以便于传递和管理。
  2. 响应结果的封装:将网络请求返回的响应结果进行封装,例如状态码、响应头、响应体等。同样,可以定义一个统一的数据结构或模型类来表示响应结果,以便于处理和解析。
  3. 错误处理的封装:对网络请求可能出现的错误进行封装和处理,例如网络连接失败、超时、服务器错误等。可以定义自定义的异常类或错误码,以及相应的错误处理机制。
  4. 拦截器的封装:如果第三方网络库支持拦截器机制,你可以封装拦截器,用于在请求发起前或响应返回后进行额外的处理,如添加身份验证、日志记录等。

响应结果封装

  1. 响应状态码:获取响应的HTTP状态码,以判断请求是否成功或出现错误。常见的状态码有200表示成功,4xx表示客户端错误,5xx表示服务器错误等。
  2. 响应头(Headers):获取响应的头部信息,如Content-Type、Authorization等。根据接口要求和需要,提取并封装相应的响应头信息。
  3. 响应体(Body):获取响应的主体数据,通常是服务器返回的具体内容。根据接口要求和数据类型,将响应体进行适当的解析和处理,可以是JSON、文本、二进制数据等。
  4. 错误处理:根据响应状态码或其他错误标识,判断响应是否包含错误信息。如果存在错误,需要将错误信息进行封装和处理,以便在前端进行展示或进一步处理。
  5. 数据转换:根据接口返回的数据类型和需求,可能需要对响应数据进行适当的转换和格式化,以便在前端进行处理和展示。
  6. 异常处理:处理网络请求过程中可能出现的异常情况,如网络错误、超时等。提供友好的提示或错误处理机制,确保用户能够得到合适的反馈。

错误处理封装

  1. 错误码(Error Code):定义一套错误码,用于标识不同类型的错误。每个错误码应具有唯一性,并且可以根据错误码快速定位和处理错误。
  2. 错误信息(Error Message):为每个错误码提供相应的错误信息,以便在错误发生时能够提供清晰的错误描述。错误信息应该简明扼要、易于理解,并且能够帮助开发者或用户快速定位问题。
  3. 异常处理机制:针对可能出现的异常情况,如网络连接失败、请求超时等,需要实现相应的异常处理机制。这可以包括使用try-catch语句捕获异常、设置超时时间、重试机制等。
  4. 错误回调或异常抛出:根据具体情况,可以选择将错误通过回调函数返回给调用方,或者抛出异常供上层代码捕获和处理。这取决于项目的架构和开发者的偏好。
  5. 友好的错误提示:对于用户可见的错误,如接口调用失败或数据获取错误,需要提供友好的错误提示,以便用户能够理解并采取适当的操作。
  6. 日志记录:在错误处理中,建议记录相关的错误日志,包括错误码、错误信息、请求参数等,以便进行故障排查和问题定位。

默认配置项

我们在使用第三方网络库时,它会有相应的默认配置项的,配置好默认配置项时,为后面请求省了很多事。

那么常见的默认网络库配置项有如下:

  1. 请求方法(HTTP Method):通常默认为 GET 方法,用于获取资源。其他常见的请求方法包括 POST、PUT、DELETE 等。
  2. 请求超时时间(Timeout):默认情况下,网络库会设置一个请求超时时间,即在指定时间内没有收到服务器响应,则认为请求超时。默认超时时间通常为几秒钟,可以根据需要进行调整。
  3. 请求头(Headers):默认情况下,网络库不会添加任何请求头。你可以自定义请求头,例如添加身份验证信息、指定数据格式等。
  4. 响应数据格式(Response Format):网络库通常默认将响应数据解析为特定的格式,如 JSON、XML 或原始文本。你可以根据需要进行解析或更改默认格式。
  5. 连接池(Connection Pooling):一些网络库可能会使用连接池来管理与服务器的连接。连接池允许重复使用已建立的连接,以提高性能和效率。

本文会 讲Flutter dio 默认配置项:

dio BaseOptions 配置项源码:

BaseOptions({
  String? method, // 请求方法,默认为null,表示使用库的默认请求方法
  Duration? connectTimeout, // 连接超时时间,默认为null,表示使用库的默认超时时间
  Duration? receiveTimeout, // 接收超时时间,默认为null,表示使用库的默认超时时间
  Duration? sendTimeout, // 发送超时时间,默认为null,表示使用库的默认超时时间
  String baseUrl = '', // 基础URL,默认为空字符串
  Map<String, dynamic>? queryParameters, // 查询参数,默认为null
  Map<String, dynamic>? extra, // 额外配置参数,默认为null
  Map<String, dynamic>? headers, // 请求头,默认为null
  ResponseType? responseType = ResponseType.json, // 响应数据格式,默认为ResponseType.json,表示解析为JSON格式
  String? contentType, // 请求的Content-Type,默认为null
  bool Function(int?)? validateStatus, // 自定义验证响应状态码的函数,默认为null
  bool? receiveDataWhenStatusError, // 当响应状态码错误时是否继续接收数据,默认为null
  bool? followRedirects, // 是否跟随重定向,默认为null
  int? maxRedirects, // 最大重定向次数,默认为null
  bool? persistentConnection, // 是否保持持久连接,默认为null
  List<int> Function(String, RequestOptions)? requestEncoder, // 请求编码器,默认为null
  String? Function(List<int>, RequestOptions, ResponseBody)? responseDecoder, // 响应解码器,默认为null
  ListFormat? listFormat, // JSON数组的解析格式,默认为null
})

Demo

import 'package:dio/dio.dart';
class HttpApi { 
// 配置基本的请求选项
  static final BaseOptions options = BaseOptions(
    baseUrl: 'http://localhost:3001/', // 设置请求的基础 URL
    method: 'GET', //默认请求方法
    connectTimeout: const Duration(seconds: 5), // 设置连接超时时间为 5 秒
    receiveTimeout: const Duration(seconds: 3), // 设置接收超时时间为 3 秒
    headers: {
      'User-Agent': 'Dio', // 设置请求头信息
    },
  );
  static Dio dio = Dio(options);
}

拦截器

在Flutter中,Dio是一个强大的HTTP客户端库,它提供了拦截器(Interceptors)机制,用于在发送请求和接收响应之前进行额外的处理。拦截器可以用于添加身份验证、日志记录、错误处理等功能。

对于每个 dio 实例,我们可以添加一个或多个拦截器,通过这些拦截器,我们可以在处理请求、响应和错误之前拦截它们或 catchError。

内置拦截器

有的网路库它会内置一些拦截器,下面是 dio 内置的拦截器:

  1. LogInterceptor:用于打印请求和响应的日志信息。它可以帮助开发者调试和监控网络请求,包括请求方法、URL、请求头、请求体、响应状态码、响应头和响应体等。
  2. InterceptorsWrapper:这是一个包装类拦截器,它可以同时包含多个拦截器,并按照添加的顺序依次执行。通过使用InterceptorsWrapper,可以方便地组合多个拦截器,实现复杂的拦截器逻辑

List<Interceptor> inters = [];
inters.add(LogInterceptor()); //添加内置拦截器
dio.interceptors.addAll(inters);

自定义拦截器

自定义过滤器需要继承 DioInterceptor类并重写其方法来实现的。

在自定义拦截器中,我们可以在onRequest方法中处理请求前的逻辑,在onResponse方法中处理接收到响应后的逻辑onError方法中处理请求发生错误时的逻辑

// 自定义拦截器
class CustomInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    // 在发送请求前的处理逻辑
    print('Request Interceptor - Request: ${options.uri}');
    print('我发送了请求啦--------');
    handler.next(options); // 继续执行下一个拦截器或发送请求
  }
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // 在接收到响应后的处理逻辑
    print('Request Interceptor - Response: ${response.statusCode}');
    print('我收到请求啦--------');
    handler.next(response); // 继续执行下一个拦截器或返回响应
  }
  @override
  // ignore: deprecated_member_use
  void onError(DioError err, ErrorInterceptorHandler handler) {
    // 在请求发生错误时的处理逻辑
    print('Request Interceptor - Error: ${err.message}');
    handler.next(err); // 继续执行下一个拦截器或抛出错误
  }
}

发起请求

上面我已经把网络库的 默认配置项,拦截器都配置好了,接下来就是开始发起请求了。我可以把发起请求做个简单封装,把可变的参数提供去,这样每次再发起请求时,只需要传递参数就可以了。

try {
      Response response =
          await dio.request<T>(url, queryParameters: params, options: options);
      return response.data;
    } catch (e) {
      print(e);
      return Future.error(e);
}

完整封装代码

/*
 * @Author: HaiJun
 * @Date: 2023-08-15 14:13:54
 * @LastEditTime: 2023-08-16 14:29:43
 * @FilePath: \flutter_demo_show\lib\utils\http.dart
 * @Description: 
 * 
 */
import 'package:dio/dio.dart';
import './CustomInterceptor.dart';
class HttpApi {
  // 配置基本的请求选项
  static final BaseOptions options = BaseOptions(
    baseUrl: 'http://localhost:3001/', // 设置请求的基础 URL
    method: 'GET', //默认请求方法
    connectTimeout: const Duration(seconds: 5), // 设置连接超时时间为 5 秒
    receiveTimeout: const Duration(seconds: 3), // 设置接收超时时间为 3 秒
    headers: {
      'User-Agent': 'Dio', // 设置请求头信息
    },
  );
  static Dio dio = Dio(options);
  static Future<T> request<T>(String url,
      {String method = "get", Map<String, dynamic>? params}) async {
    // 1请求的单独配置
    final options = Options(method: method);
    // 2 添加一个拦截器
    Interceptor inter = InterceptorsWrapper(
      onRequest: (options, handler) {
        return handler.next(options);
      },
      onResponse: (e, handler) {
        print(e);
        return handler.next(e);
      },
      onError: (e, handler) {
        print(e);
        return handler.next(e);
      },
    );
    List<Interceptor> inters = [];
    inters.add(CustomInterceptor()); //添加自定义拦截器
    inters.add(LogInterceptor()); //添加内置拦截器
    dio.interceptors.addAll(inters);
    // 3 发起网络请求
    try {
      Response response =
          await dio.request<T>(url, queryParameters: params, options: options);
      print("测试");
      print(url);
      return response.data;
    } catch (e) {
      print(e);
      return Future.error(e);
    }
  }
}

调用请求

把封装好的文件导入进来,

import 'package:flutter/material.dart';
import 'utils/http.dart';
class MyNetwork extends StatefulWidget {
  const MyNetwork({super.key});
  @override
  State<MyNetwork> createState() => _MyNetworkState();
}
class _MyNetworkState extends State<MyNetwork> {
  void getData() async {
    print("发起请求");
    var responseData = await HttpApi.request('book');
    print(responseData);
  }
  @override
  Widget build(BuildContext context) {
    return Container(
        child: Column(children: [
      ElevatedButton(
          onPressed: () {
            getData();
          },
          child: const Text("发起请求"))
    ]));
  }
}

utils/http.dart文件中,我们封装了 dio ,创建了dio示例,传入了默认配置项,并且绑定了拦截器,在发起请求时,也会走请求拦截器,看参数是否合法,后会进入响应拦截器,状态码是否对以及不同状态码返回不同内容,最后将返回结果数据抛给客户端响应。

utils/http.dart文件中, 有一个 request异步 静态(static)方法,它提供了请求时需要填的必填参数和可选参数,当我们使用时,可以通过 类名.方法名 即可调用发起请求了。

请求返回内容

相关文章
|
7天前
|
存储 运维 安全
云上金融量化策略回测方案与最佳实践
2024年11月29日,阿里云在上海举办金融量化策略回测Workshop,汇聚多位行业专家,围绕量化投资的最佳实践、数据隐私安全、量化策略回测方案等议题进行深入探讨。活动特别设计了动手实践环节,帮助参会者亲身体验阿里云产品功能,涵盖EHPC量化回测和Argo Workflows量化回测两大主题,旨在提升量化投研效率与安全性。
云上金融量化策略回测方案与最佳实践
|
9天前
|
人工智能 自然语言处理 前端开发
从0开始打造一款APP:前端+搭建本机服务,定制暖冬卫衣先到先得
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。
8434 20
|
13天前
|
Cloud Native Apache 流计算
资料合集|Flink Forward Asia 2024 上海站
Apache Flink 年度技术盛会聚焦“回顾过去,展望未来”,涵盖流式湖仓、流批一体、Data+AI 等八大核心议题,近百家厂商参与,深入探讨前沿技术发展。小松鼠为大家整理了 FFA 2024 演讲 PPT ,可在线阅读和下载。
4552 11
资料合集|Flink Forward Asia 2024 上海站
|
13天前
|
自然语言处理 数据可视化 API
Qwen系列模型+GraphRAG/LightRAG/Kotaemon从0开始构建中医方剂大模型知识图谱问答
本文详细记录了作者在短时间内尝试构建中医药知识图谱的过程,涵盖了GraphRAG、LightRAG和Kotaemon三种图RAG架构的对比与应用。通过实际操作,作者不仅展示了如何利用这些工具构建知识图谱,还指出了每种工具的优势和局限性。尽管初步构建的知识图谱在数据处理、实体识别和关系抽取等方面存在不足,但为后续的优化和改进提供了宝贵的经验和方向。此外,文章强调了知识图谱构建不仅仅是技术问题,还需要深入整合领域知识和满足用户需求,体现了跨学科合作的重要性。
|
21天前
|
人工智能 自动驾驶 大数据
预告 | 阿里云邀您参加2024中国生成式AI大会上海站,马上报名
大会以“智能跃进 创造无限”为主题,设置主会场峰会、分会场研讨会及展览区,聚焦大模型、AI Infra等热点议题。阿里云智算集群产品解决方案负责人丛培岩将出席并发表《高性能智算集群设计思考与实践》主题演讲。观众报名现已开放。
|
8天前
|
人工智能 容器
三句话开发一个刮刮乐小游戏!暖ta一整个冬天!
本文介绍了如何利用千问开发一款情侣刮刮乐小游戏,通过三步简单指令实现从单个功能到整体框架,再到多端优化的过程,旨在为生活增添乐趣,促进情感交流。在线体验地址已提供,鼓励读者动手尝试,探索编程与AI结合的无限可能。
三句话开发一个刮刮乐小游戏!暖ta一整个冬天!
|
1月前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
104586 10
|
8天前
|
消息中间件 人工智能 运维
12月更文特别场——寻找用云高手,分享云&AI实践
我们寻找你,用云高手,欢迎分享你的真知灼见!
717 44
|
6天前
|
弹性计算 运维 监控
阿里云云服务诊断工具:合作伙伴架构师的深度洞察与优化建议
作为阿里云的合作伙伴架构师,我深入体验了其云服务诊断工具,该工具通过实时监控与历史趋势分析,自动化检查并提供详细的诊断报告,极大提升了运维效率和系统稳定性,特别在处理ECS实例资源不可用等问题时表现突出。此外,它支持预防性维护,帮助识别潜在问题,减少业务中断。尽管如此,仍建议增强诊断效能、扩大云产品覆盖范围、提供自定义诊断选项、加强教育与培训资源、集成第三方工具,以进一步提升用户体验。
639 243
|
3天前
|
弹性计算 运维 监控
云服务测评 | 基于云服务诊断全方位监管云产品
本文介绍了阿里云的云服务诊断功能,包括健康状态和诊断两大核心功能。作者通过个人账号体验了该服务,指出其在监控云资源状态和快速排查异常方面的优势,同时也提出了一些改进建议,如增加告警配置入口和扩大诊断范围等。