Flutter网络请求与dio实战指南
  pldY3AmarceX 2023年11月19日 48 0

当在Flutter中进行网络请求时,dio是一个强大且常用的网络请求库。以下是使用dio实现网络请求的基本配置,包括GET和POST请求,以及文件上传和下载的功能。

Dio 的基本配置

首先,确保在pubspec.yaml文件中添加dio库的依赖:

dependencies:
  # https://github.com/flutterchina/dio
  dio: ^5.3.3

然后运行flutter pub get安装依赖。


接下来,需要在 Dart 文件中导入 dio 包:

import 'package:dio/dio.dart';
创建 Dio 实例

在使用 dio 之前,需要创建一个 Dio 实例。可以在整个应用程序中共享这个实例,也可以在需要的地方单独创建。

Dio dio = Dio();
发起 GET 请求
try {
  Response response = await dio.get('https://api.example.com/data');
  print(response.data);
} catch (e) {
  print('Error: $e');
}
发起 POST 请求
try {
  Response response = await dio.post(
    'https://api.example.com/post',
    data: {'key': 'value'},
  );
  print(response.data);
} catch (e) {
  print('Error: $e');
}
文件上传
try {
  FormData formData = FormData.fromMap({
    'file': await MultipartFile.fromFile('/path/to/file.txt', filename: 'upload.txt'),
    'other_field': 'other_value',
  });

  Response response = await dio.post(
    'https://api.example.com/upload',
    data: formData,
  );

  print(response.data);
} catch (e) {
  print('Error: $e');
}
文件下载
try {
  Response response = await dio.download(
    'https://api.example.com/file',
    '/path/to/save/file.txt',
    onReceiveProgress: (received, total) {
      if (total != -1) {
        print((received / total * 100).toStringAsFixed(0) + "%");
      }
    },
  );

  print(response.data);
} catch (e) {
  print('Error: $e');
}
配置 Dio
Dio dio = Dio(BaseOptions(
  baseUrl: 'https://api.example.com',
  connectTimeout: 5000, // 连接超时时间
  receiveTimeout: 3000, // 接收超时时间
  headers: {'Authorization': 'Bearer YourToken'}, // 全局请求头
  contentType: Headers.formUrlEncodedContentType, // 设置请求格式
  responseType: ResponseType.json, // 设置响应格式
));
下面是一个完整工具类代码,供大家参考使用:

import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';

import 'package:get/get.dart' as getx;

import '../../weight/loading.dart';
import 'api.dart';

class HttpUtil {
  static HttpUtil? instance;
  late Dio dio;
  late BaseOptions options;

  CancelToken cancelToken = CancelToken();

  static HttpUtil getInstance() {
    instance ??= HttpUtil();
    return instance!;
  }

  /*
   * config it and create
   */
  HttpUtil() {
    //BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
    options = BaseOptions(
      //请求基地址,可以包含子路径
      baseUrl: Api.BASE_URL,
      //连接服务器超时时间,单位是秒.
      connectTimeout: const Duration(seconds: 10),
      //响应流上前后两次接受到数据的间隔,单位为秒。
      receiveTimeout: const Duration(seconds: 5),
      //Http请求头.
      headers: {
        "version": "1.0.0"
      },
      //请求的Content-Type,默认值是"application/json; charset=utf-8",Headers.formUrlEncodedContentType会自动编码请求体.
      contentType: Headers.formUrlEncodedContentType,
      //表示期望以那种格式(方式)接受响应数据。接受四种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
      responseType: ResponseType.plain,
    );

    dio = Dio(options);

    //Cookie管理
    final cookieJar = CookieJar();
    dio.interceptors.add(CookieManager(cookieJar));

    //添加拦截器
    dio.interceptors.add(InterceptorsWrapper(
        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
      print("请求之前 header = ${options.headers.toString()}");
      // 打印查询参数
      if (options.queryParameters != null) {
        print("Query Parameters: ${options.queryParameters}");
      }
      // 如果你想完成请求并返回一些自定义数据,你可以使用 `handler.resolve(response)`。
      // 如果你想终止请求并触发一个错误,你可以使用 `handler.reject(error)`。
      return handler.next(options); //continue
    }, onResponse: (Response response, ResponseInterceptorHandler handler) {
      print("响应之前");
      // 如果你想终止请求并触发一个错误,你可以使用 `handler.reject(error)`。
      return handler.next(response); // continue
    }, onError: (DioException e, ErrorInterceptorHandler handler) {
      print("错误之前");
      // 如果你想完成请求并返回一些自定义数据,你可以使用 `handler.resolve(response)`。
      return handler.next(e);
    }));
  }


  /*
   * GET请求
   */
  Future<Response?> getRequest(
      String url, {
        Map<String, dynamic>? parameters,
        Options? options,
        CancelToken? cancelToken,
        void Function(Response response)? onSuccess,
        void Function(String error)? onError,
        bool showLoading = false,
        String loadingMsg = '请稍后...',
      }) async {
    try {
      _toggleLoading(showLoading, loadingMsg);
      final response = await dio.get(
        url,
        queryParameters: parameters,
        options: options,
        cancelToken: cancelToken,
      );
      _toggleLoading(showLoading, loadingMsg);
      if (onSuccess != null) {
        if (response.statusCode == 200) {
          onSuccess(response);
        } else {
          // 处理其他状态码的逻辑
          // ...
        }
      }
      return response;
    } on DioException catch (e) {
      _toggleLoading(showLoading, loadingMsg);
      if (onError != null) {
        onError(_formatError(e));
      }
      return null;
    }
  }

  void _toggleLoading(bool showLoading, String loadingMsg) {
    if (showLoading) {
      LoadingIndicator.show(getx.Get.context!, title: loadingMsg);
    } else {
      LoadingIndicator.hide();
    }
  }

  /*
   * POST请求
   */
  Future<Response?> postRequest(
      String url, {
        Map<String, dynamic>? parameters,
        dynamic data,
        Options? options,
        CancelToken? cancelToken,
        void Function(Response response)? onSuccess,
        void Function(String error)? onError,
        bool showLoading = false,
        String loadingMsg = '请稍后...',
      }) async {
    try {
      _toggleLoading(showLoading, loadingMsg);
      final response = await dio.post(
        url,
        data: data,
        queryParameters: parameters,
        options: options,
        cancelToken: cancelToken,
      );
      _toggleLoading(showLoading, loadingMsg);

      if (onSuccess != null) {
        if (response.statusCode == 200) {
          onSuccess(response);
        } else {
          // 处理其他状态码的逻辑
          // ...
        }
      }
      return response;
    } on DioException catch (e) {
      _toggleLoading(showLoading, loadingMsg);
      if (onError != null) {
        onError(_formatError(e));
      }
      return null;
    }
  }

  /*
   * 下载文件
   */
  Future<dynamic> downloadFile(String urlPath, String savePath) async {
    Response? response;
    try {
      response = await dio.download(
        urlPath,
        savePath,
        onReceiveProgress: _onDownloadProgress,
      );
    } on DioError catch (e) {
      _formatError(e);
    }
    return response?.data;
  }

  // 提取进度回调
  void _onDownloadProgress(int count, int total) {
    // 进度
    print("$count $total");
  }

  /*
   * 上传文件
   */
  Future<void> uploadFile(url, FormData formData,
      {String? accessToken,
        void Function(Response response)? onSuccess,
        void Function(String error)? onError}) async {
    try {
      late Response response;
      response = await dio.post(
        url,
        data: formData,
        options: Options(
          headers: {'Authorization': 'Bearer $accessToken'},
        ),
      );

      if (onSuccess != null) {
        if (response.statusCode == 200) {
          onSuccess(response);
        } else {
          // 处理其他状态码的逻辑
          // ...
        }
      }
      print('上传成功: ${response.data}');
    } on DioException catch (e) {
      if (onError != null) {
        onError(_formatError(e));
      }
      print('上传失败: $e');
    }
  }

  /*
   * error统一处理
   */
  String _formatError(DioException e) {

    String errorMsg = '';
    if (e.type == DioExceptionType.connectionTimeout) {
      errorMsg =  '连接超时';
    } else if (e.type == DioExceptionType.sendTimeout) {
      errorMsg =  '请求超时';
    } else if (e.type == DioExceptionType.receiveTimeout) {
      errorMsg =  '响应超时';
    } else if (e.type == DioExceptionType.badResponse) {
      errorMsg =  '错误响应';
    } else if (e.type == DioExceptionType.cancel) {
      errorMsg =  '请求取消';
    } else if (e.type == DioExceptionType.connectionError) {
      errorMsg =  '无法连接服务器';
    } else {
      errorMsg =  '未知错误';
    }
    print(errorMsg);
    return errorMsg;
  }

  /*
   * 取消请求
   *
   * 同一个cancel token 可以用于多个请求,当一个cancel token取消时,所有使用该cancel token的请求都会被取消。
   * 所以参数可选
   */
  void cancelRequests(CancelToken token) {
    token.cancel("cancelled");
  }
}

代码中使用的dialog可以参考该链接



【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月19日 0

暂无评论

推荐阅读
  a1POfVYpMOW2   2023年12月23日   135   0   0 flutterciflutterideciide
pldY3AmarceX