Flutter 开发-网络请求库 Dio 封装

1,345 阅读2分钟

Flutter 开发中,常用的网络请求库为 Dio。本文对 Dio 进行简单封装。

base_res.dart

import 'package:dio/dio.dart';

class BaseResponse {
  // 通用参数,可根据实际业务修改
  late int code;
  late String message;
  late dynamic data;
  // 业务请求是否成功
  late bool success;
  // Dio 返回的原始 Response 数据
  Response? ores;

  BaseResponse({
    required this.code,
    required this.message,
    required this.data,
    required this.success,
    required this.ores,
  });

  BaseResponse.fromJson(dynamic json) {
    code = json?['code'] ?? -1;
    message = json?['message'] ?? '';
    data = json?['data'] ?? '';
    success = code == 0 ? true : false;
  }
}

api.dart

import 'package:flutter/foundation.dart';

class Api {
  static const baseUrl = kDebugMode ? '' : '';

  // login
  static const loginUrl = '';
}

dio_intercept.dart

import 'package:dio/dio.dart';

class AuthInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    // 此处根据业务逻辑,自行判断处理
    if ('token' != '') {
      options.headers['token'] = 'token';
    }
    super.onRequest(options, handler);
  }
}

class LogInterceptor extends Interceptor {
  late DateTime _startTime;
  late DateTime _endTime;

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    _startTime = DateTime.now();
    // 此处根据业务逻辑,自行增加 requestUrl requestMethod headers queryParameters 等参数的打印
    print('---Request Start---');
    super.onRequest(options, handler);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    _endTime = DateTime.now();
    final int duration = _endTime.difference(_startTime).inMilliseconds;
    print('---Request End: 耗时 $duration 毫秒---');
    super.onResponse(response, handler);
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    print('---Resuest Error: ${err.toString()}');
    super.onError(err, handler);
  }
}

dio_utils.dart

import 'dart:io';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_application_dio/net/api.dart';
import 'package:flutter_application_dio/net/base_res.dart';
import 'package:flutter_application_dio/net/dio_intercept.dart' as interceptor;
import 'package:flutter_application_dio/net/dio_wrap.dart';

class HttpUtils {
  static final HttpUtils _instance = HttpUtils._();

  static HttpUtils get instance => HttpUtils();

  factory HttpUtils() => _instance;

  static late Dio _dio;

  Dio get dio => _dio;

  HttpUtils._() {
    // 构造 Dio options
    final BaseOptions options = BaseOptions(
      connectTimeout: 15000,
      receiveTimeout: 15000,
      sendTimeout: 10000,
      responseType: ResponseType.plain,
      validateStatus: (_) => true,
      baseUrl: Api.baseUrl,
    );

    // 实例化 Dio
    _dio = Dio(options);

    // 忽略 https 证书校验
    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
        (HttpClient client) {
      client.badCertificateCallback =
          (X509Certificate cert, String host, int port) => true;
      return client;
    };

    // 添加迭代器
    _dio.interceptors.add(interceptor.AuthInterceptor());
    if (kDebugMode) {
      _dio.interceptors.add(interceptor.LogInterceptor());
    }
  }

  Future<BaseResponse> _request(
    String url, {
    String? method = 'POST',
    dynamic params,
    bool tips = false,
    void Function(int, int)? onSendProgress,
    void Function(int, int)? onReceiveProgress,
  }) async {
    late BaseResponse response;
    try {
      if (tips) {
        // 展示 loading
      }
      late Response<dynamic> res;
      if (method == 'GET') {
        res = await _dio.get(url, queryParameters: params);
      } else if (method == 'UPLOAD') {
        FormData formData = FormData.fromMap(params);
        res = await _dio.post(
          url,
          data: formData,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress,
        );
      } else {
        res = await _dio.post(
          url,
          data: params,
        );
      }
      response = DioWrapper.responseWrapper(res);
    } catch (e) {
      response = DioWrapper.errorWrapper(e);
    } finally {
      // 隐藏 loading
    }
    return response;
  }

  // GET
  Future<BaseResponse> get(
    String url, {
    dynamic params,
    bool tips = false,
  }) async {
    return _request(
      url,
      method: 'GET',
      params: params,
      tips: tips,
    );
  }

  // POST
  Future<BaseResponse> post(
    String url, {
    dynamic params,
    bool tips = false,
  }) async {
    return _request(
      url,
      method: 'POST',
      params: params,
      tips: tips,
    );
  }

  // UPLOAD
  Future<BaseResponse> upload(
    String url, {
    dynamic params,
    bool tips = false,
    void Function(int, int)? onSendProgress,
    void Function(int, int)? onReceiveProgress,
  }) async {
    return _request(
      url,
      method: 'UPLOAD',
      params: params,
      tips: tips,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }
}

dio_wrapper.dart

import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter_application_dio/net/base_res.dart';

class DioWrapper {
  static BaseResponse errorWrapper(Object e) {
    return BaseResponse(
      code: -1,
      message: e is DioError ? _dioErrorWrapper(e) : '未知错误',
      data: '',
      success: false,
      ores: null,
    );
  }

  static String _dioErrorWrapper(DioError error) {
    switch (error.type) {
      case DioErrorType.connectTimeout:
        return '连接服务器超时';
      case DioErrorType.sendTimeout:
        return '连接服务器超时';
      case DioErrorType.receiveTimeout:
        return '连接服务器超时';
      case DioErrorType.cancel:
        return '连接被取消';
      default:
        return '未知错误';
    }
  }

  static BaseResponse responseWrapper(Response response) {
    // 此处如果数据比较大,可以使用 compute 放在后台计算
    final res = jsonDecode(response.data);
    if (response.statusCode == 200) {
      final BaseResponse wrapres = BaseResponse.fromJson(res);
      wrapres.ores = response;
      return wrapres;
    } else {
      var msg = res["error_description"] ?? '';
      if (response.statusCode == 401) {
        msg = 'token失效';
      }
      return BaseResponse(
        code: -1,
        success: false,
        message: msg,
        data: "",
        ores: response,
      );
    }
  }
}

使用方法

  void login() async {
    final res = await HttpUtils.instance.post(
      Api.loginUrl,
      params: {},
      tips: true,
    );
    print(res);
  }