Skip to content

Dio官方地址

pubdev地址:https://pub.dev/packages/dio 中文README:https://github.com/cfug/dio/blob/main/dio/README-ZH.md

简单使用

引入依赖

dart
dio: ^5.4.0

导入dio框架 image.png

Get请求

image.png

post请求

image.png

请求数据并渲染界面

dart
class DioPage extends StatefulWidget {
  const DioPage({Key? key}) : super(key: key);

  @override
  State<DioPage> createState() => _DioPageState();
}

class _DioPageState extends State<DioPage> {
  final Dio dio = Dio();

  String? result;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("dio请求"),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () => {_get()}, child: const Text("get请求")),
            Text(
              result ?? "无数据",
              style: const TextStyle(fontSize: 12),
            ),
          ],
        ),
      ));
  }

  _get() async {
    Response response = (await dio.get("http://www.baidu.com"));
    setState(() {
      result = response.data.toString();
    });
  }
}

封装

单例模式

首先创建单例对象,这里可以使用dart的语法糖

java
  static DioInstance? _instance; //静态私有变量
  DioInstance._(); //静态的私有构造方法

//实例为空则初始化
  static DioInstance getInstance() {
    return _instance ??= DioInstance._();
  }

image.png 初始化dio,配置一些基本参数 image.png

配置请求方法为静态字符串变量 image.png 封装get和post请求,这里直接返回的是Future<Response>

java
  Future<Response> get({
    required String path,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }){

    return _dio.get(path,
    queryParameters: params,
    options: options ?? Options(
      method: HttpMethod.GET,
      receiveTimeout: _defaultTime,
      sendTimeout: _defaultTime
    ),
    cancelToken: cancelToken);
  }

  Future<Response> post({
    required String path,
    Object? data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }){

    return _dio.post(path,
        data: data,
        queryParameters: params,
        options: options ?? Options(
            method: HttpMethod.POST,
            receiveTimeout: _defaultTime,
            sendTimeout: _defaultTime
        ),
        cancelToken: cancelToken);
  }

初始化DioInstance,在启动app时开始初始化 image.png

输出日志

上面的get和post的返回类型是Future<Response>,但是我们展示层其实只用关心Response对象下的data即可。 所以可以修改get和post的返回类型,直接返回Response的data 并且添加日志输出

java
get({
    required String path,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }) async{
    Response? response;
    try {
      response = await _dio.get(path,
          queryParameters: params,
          options: options ?? Options(
              method: HttpMethod.GET,
              receiveTimeout: _defaultTime,
              sendTimeout: _defaultTime
          ),
          cancelToken: cancelToken);
      print('get success---------${response.realUri}');
      print('get success---------${response.statusCode}');
      print('get success---------${response.data}');
    }on DioError catch(e){
      print('get error---------$e');
      formatError(e);
    }
    return response?.data;

  }

  post({
    required String path,
    Object? data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }) async{
    Response? response;
    try {
      response = await _dio.post(path,
          data: data,
          queryParameters: params,
          options: options ?? Options(
              method: HttpMethod.POST,
              receiveTimeout: _defaultTime,
              sendTimeout: _defaultTime
          ),
          cancelToken: cancelToken);
      print('post success---------${response.realUri}');
      print('post success---------${response.statusCode}');
      print('post success---------${response.data}');
    }on DioError catch(e){
      print('post error---------$e');
      formatError(e);
    }
    return response?.data;
  }

添加拦截器

Dio通过也支持配置拦截器,那么可以添加拦截器来实现打印日志输出的功能。 除此之外还可以通过配置拦截器来统一异常处理。 实现一个打印日志输出的拦截器,继承InterceptorsWrapper方法,并实现其中的三个方法,分别代表

  1. 获取发起请求的信息onRequest
  2. 获取请求得到的信息onResponse
  3. 获取请求异常的信息onError
java
class PrintLogInterceptor extends InterceptorsWrapper{


  //发起请求的信息
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    log("\nrequest----------->");
    options.headers?.forEach((key, value) { 
      log("请求头信息:key=$key value=${value.toString()}");
    });
    log("path:${options.uri}");
    log("method:${options.method}");
    log("data:${options.data}");
    log("queryParams:${options.queryParameters.toString()}");
    log("<----------request\n");
    super.onRequest(options, handler);
  }

  //请求得到的结果
@override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
  log("\nresponse----------->");
  log("path:${response.realUri}");
  log("header:${response.headers.toString()}");
  log("statusMessage:${response.statusMessage}");
  log("statusCode:${response.statusCode}");
  log("extra:${response.extra.toString()}");
  log("data:${response.data.toString()}");
  log("<----------response\n");
    super.onResponse(response, handler);
  }


  //请求异常
@override
  void onError(DioError err, ErrorInterceptorHandler handler) {
  log("\nonError----------->");
  log("err:${err.toString()}");
  log("<----------onError\n");
    super.onError(err, handler);
  }
}

然后就是使用这个拦截器 image.png 重新运行可以看到控制台已经打印出信息 image.png

添加异常拦截器

因为数据返回具有一定的格式,我们可以创建一个数据基类,提前将返回的数据解析成固定的格式,然后通过判断其中的errorCode字段来提前对数据进行拦截处理,如果错误码不对,可以提前拦截数据去做相应的逻辑。 如果errorCode字段正常,则对数据进行进一步解析

java
///
/// @DIR_PATH:lib/http
/// @TIME:2024/6/6 21:00
/// @AUTHOR:starr
/// 创建数据基类,提前将返回的数据解析成固定的格式
class BaseModel<T> {
  T? data;
  int? errorCode;
  String? errorMsg;

  BaseModel.fromJson(dynamic json){
    data = json['data'];
    errorCode = json['errorCode'];
    errorMsg = json['errorMsg'];
  }
}
java
import 'package:dio/dio.dart';
import 'package:flutter_base/http/base_model.dart';
import 'package:oktoast/oktoast.dart';

///
/// @DIR_PATH:lib/http
/// @TIME:2024/6/6 21:03
/// @AUTHOR:starr
///
///
class ResponseInterceptor extends InterceptorsWrapper{

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    if(response.statusCode==200){

      try{
        var rsp = BaseModel.fromJson(response.data);
        if(rsp.errorCode==0){
          if(rsp.data==null){
            //解析成功,但是没有数据
            handler.next(Response(requestOptions: response.requestOptions,data: true));
          }else{
            //解析成功,并且有数据
            handler.next(Response(requestOptions: response.requestOptions,data: rsp.data));
          }
          //未登录
        }else if(rsp.errorCode == -1001) {
          handler.reject(DioException(requestOptions: response.requestOptions,message: "未登录"));
          showToast("未登录");
        }else{
          //未知错误
          handler.reject(DioException(requestOptions: response.requestOptions,message: "未知错误"));
          showToast("未知错误");
        }
      }catch (e){
        handler.reject(DioException(requestOptions: response.requestOptions,message: "$e"));
      }
    }else{
      handler.reject(DioException(requestOptions: response.requestOptions));
    }
  }
}