Flutter - 如何设计一个可扩展的网络请求框架

249 阅读1分钟

网络请求框架设计目标:

● 支持网络库插拔设计,不干扰业务层

● 简洁易用,支持配置来进行请求

● Adapter设计,可扩展性强

● 统一异常和返回处理

网络请求设计框架

1.  定义基础请求抽象类

enum HttpMethod { get, post, delete, put }

/// 基础请求
abstract class BaseRequest {
  var pathParams;

  var useHttpRequest = true;
// 域名
  String authority() {
    return "rlmqj.wiremockapi.cloud";
  }

  HttpMethod httpMethod();

  String path();
  String url() {
    Uri uri;
    var pathString = path();
    // 拼接path参数
    if (pathParams != null) {
      if (path().endsWith('/')) {
        pathString = '${path()}$pathParams';
      } else {
        pathString = '${path()}/$pathParams';
      }
    }

    // http和https切换
    if (useHttpRequest) {
      uri = Uri.https(authority(), pathString, paramas);
    } else {
      uri = Uri.http(authority(), pathString, paramas);
    }
    print('url:${uri.toString()}');
    return uri.toString();
  }

  bool needLogin();
  // 参数
  Map<String, String> paramas = Map();

  /// 添加参数
  BaseRequest add(String k, Object v) {
    paramas[k] = v.toString();
    return this;
  }

  /// header参数
  Map<String, String> header = Map();
  BaseRequest addHeader(String k, Object v) {
    paramas[k] = v.toString();
    return this;
  }
}

2.  定义网络请求工厂方法

import 'package:flutter_application_1/NetworkKit/DioAdapter.dart';
import 'package:flutter_application_1/NetworkKit/NetError.dart';
import 'package:flutter_application_1/NetworkKit/NetworkAdaptor.dart';
import 'package:flutter_application_1/NetworkKit/request.dart';

class NetworkProvider {
  // 私有初始化
  // 私有的命名构造函数
  NetworkProvider._internal();

  // 使用 late 关键字实现懒加载并确保 null 安全
  static final NetworkProvider _instance = NetworkProvider._internal();

  // 提供一个工厂构造函数来返回唯一的实例
  factory NetworkProvider() {
    return _instance;
  }

  // 请求方法
  Future fire(BaseRequest request) async {
    NetResponse? response;
    var error;
    try {
      response = await send(request);
    } on NetError catch (e) {
      error = e;
      response = e.data;
      printLog(e.message);
    } catch (e) {
      // 其他异常
      error = e;
      printLog(e);
    }
    if (response == null) {
      printLog(error);
    }
    // var response = await send(request);
    var result = response?.data;
    var status = response?.statusCode;
    switch (status) {
      case 200:
        printLog(result);
        return result;
      case 401:
        throw NeedLogin();
      case 403:
        throw NeedAuth();
      default:
        throw Exception();
    }
  }

  Future<dynamic> send<T>(BaseRequest request) async {
    // print('url:${request.url()}');
    // print('method:${request.httpMethod()}');
    // request.addHeader('token', '123');
    // print('header:${request.header}');
    // 使用Mock发送数据
    // Networkadaptor adapter = MockAdapter();
    // return adapter.send(request);

    // 使用Dio进行网络请求
    Dioadapter adapter = Dioadapter();
    return adapter.send(request);
  }

  void printLog(log) {
    print('net: ${log.toString()}');
  }
}

3.  定义网络请求返回数据格式,定义请求工厂抽象类

import 'dart:convert';

import 'package:flutter_application_1/NetworkKit/request.dart';

/// 同一网络层返回格式

class NetResponse {
  NetResponse(
      {this.data,
      this.request,
      this.statusCode,
      this.statusMessage,
      this.extra});

  Map<String, dynamic>? data;
  BaseRequest? request;
  int? statusCode;
  String? statusMessage;
  Map<String, dynamic>? extra;

  @override
  String toString() {
    if (data is Map) {
      return json.encode(data);
    }
    return data.toString();
  }
}

/// 网络请求Adapter类
abstract class Networkadaptor {
  Future<NetResponse> send(BaseRequest request);
}

// 实现三方库Dio网络请求方法

import 'package:dio/dio.dart';
import 'package:flutter_application_1/NetworkKit/NetError.dart';
import 'package:flutter_application_1/NetworkKit/request.dart';

import 'NetworkAdaptor.dart';

class Dioadapter extends Networkadaptor {
  @override
  Future<NetResponse> send(BaseRequest request) async {
    var response, options = Options(headers: request.header);
    final dio = Dio();
    var error;
    try {
      switch (request.httpMethod()) {
        case HttpMethod.get:
          response = await dio.get(request.url(), options: options);
          break;
        case HttpMethod.post:
          response = await dio.post(request.url(),
              data: request.paramas, options: options);
          break;
        case HttpMethod.delete:
          response = await dio.delete(request.url(),
              data: request.paramas, options: options);
          break;
        default:
      }
    } on DioException catch (e) {
      error = e;
      response = e.response;
    }
    if (error != null) {
      /// 抛出NetError
      throw NetError(response.statusCode, error.toString());
    }

    return buildRes(response, request);
  }

  NetResponse buildRes(Response response, BaseRequest request) {
    // 确保 data 的类型是 Map<String, dynamic>
    var data = response.data;

    // 使用指定的泛型类型创建 NetResponse 对象
    NetResponse myResponse = NetResponse(
      data: data,
      request: request,
      statusCode: response.statusCode,
      statusMessage: response.statusMessage,
    );
    return myResponse;
  }
}