Flutter学习-GetX-08 GetContact

1,966 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

本文主要介绍Getx中GetContact,它可以便捷的通过http或websockets进行前后台通信。

1. 自定义配置

使用GetContact通常可以用于网络请求或者通信,这里以网络请求为例

先看下GetContact组成,提供了请求时间,最大请求次数等。

image.png

同时对httpClient进行了封装,我们可以设置baseUrl,post等请求。

image.png

GetConnect具有多种自定义配置。你可以配置base Url,配置响应,配置请求,添加权限验证,甚至是尝试认证的次数,除此之外,还可以定义一个标准的解码器,该解码器将把您的所有请求转换为您的模型,而不需要任何额外的配置。

我们创建一个基础的网络请求继承于GetConnect

class Net extends GetConnect {
  Net() : super(timeout: const Duration(seconds: 30), userAgent: 'Sesame-Client') {
    httpClient.addRequestModifier<Object?>((request) async {
      _logRequest(request);
      await _setupHeader(request);
      return request;
    });
  }

  @override
  String get baseUrl => currentEnvironment.host;

  @override
  Decoder<NetResponse> get defaultDecoder => (data) {
        log("---- 响应 ----\n$data");
        try {
          return NetResponse.fromJson(data);
        } catch (error) {
          return NetResponse(NetCode.serverError, null)..message = '服务端未知错误';
        }
      };

  String get _platform {
    if (Platform.isIOS) {
      return 'iOS';
    } else if (Platform.isAndroid) {
      return 'android';
    } else {
      return 'web';
    }
  }

  Future _setupHeader(Request request) async {
    request.headers['Sesame-Platform'] = _platform;
    final token = await StoreToken.getToken();
    if (token != null) request.headers['Authorization'] = token;
  }

  void _logRequest(Request request) async {
    var str = "---- 请求 ----\nmethod: ${request.method}\nurl: ${request.url}\nquery: ${request.url.queryParameters}";
    if (request.method != 'post' || request.headers['content-type'] != 'application/json') {
      log(str);
      return;
    }
    const decoder = Utf8Decoder();
    List<List<int>> bodyBytes = [];
    request.bodyBytes.asBroadcastStream(onListen: (subscribe) {
      subscribe.onData((data) => bodyBytes.add(data));
      subscribe.onDone(() {
        str += '\nbody: ${(bodyBytes.map((e) => decoder.convert(e)).join())}';
        log(str);
      });
    });
  }
}

通过addRequestModifier进行请求拦截,添加一些日志打印以及请求头设置。addResponseModifier响应拦截处理我们的请求结果,这是使用的defaultDecoder进行解码, NetResponse为我们自定义的请求体格式,可以定义一些约定好的状态code,通过catch处理我们的错误状态。

image.png

2. 网络请求

你能轻松的通过extend GetConnect就能使用GET/POST/PUT/DELETE/SOCKET方法与你的Rest API或websockets通信。

class UserProvider extends GetConnect {
  // Get request
  Future<Response> getUser(int id) => get('http://youapi/users/$id');
  // Post request
  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);
  // Post request with File
  Future<Response<CasesModel>> postCases(List<int> image) {
    final form = FormData({
      'file': MultipartFile(image, filename: 'avatar.png'),
      'otherFile': MultipartFile(image, filename: 'cover.png'),
    });
    return post('http://youapi/users/upload', form);
  }

  GetSocket userMessages() {
    return socket('https://yourapi/users/socket');
  }
}
  • 自定义
bool get shouldRequest => true;

Future? request<T>({required ValueGetter<Future<T>> api, ValueSetter<T>? success, ValueSetter<Error>? fail}) async {
  if (!shouldRequest) {
    EasyLoading.showToast('请完善信息后重试');
    return;
  }

  EasyLoading.show();
  return api().then((value) {
    EasyLoading.dismiss();
    if (success != null) success(value);
  }).catchError((error) {
    EasyLoading.dismiss();
    EasyLoading.showToast(error.toString());
    if (fail != null) fail(error);
    if (!const bool.fromEnvironment("dart.vm.product")) throw error;
  });
}

Future<T> get<T>(String uri, Decoder<T> decoder, {Map<String, dynamic>? query}) async {
  final res = (await net.get<NetResponse>(uri, query: query, decoder: net.defaultDecoder)).body;
  return _parse(res, decoder);
}

Future<T> post<T>(String uri, Map<String, dynamic> body, Decoder<T> decoder) async {
  print(body);
  final res =
      (await net.post<NetResponse>(uri, body, contentType: 'application/json', decoder: net.defaultDecoder)).body;
  return _parse(res, decoder);
}

Future<T> patch<T>(String uri, Map<String, dynamic> body, Decoder<T> decoder) async {
  final res =
      (await net.patch<NetResponse>(uri, body, contentType: 'application/json', decoder: net.defaultDecoder)).body;
  return _parse(res, decoder);
}

Future<T> delete<T>(String uri, Map<String, dynamic>? query, Decoder<T> decoder) async {
  final res = (await net.delete<NetResponse>(uri, query: query, decoder: net.defaultDecoder)).body;
  return _parse(res, decoder);
}

使用

void requestData() {
 get('home/chat/list', (data) => (data as List<dynamic>).map((e) => ChatModel.fromJson(e)).toList()).then((value) => {
   listData.value = value
 });
}

image.png

3. Getx+Dio

我们也可以使用Dio进行网络请求,这里简单封装下

class HttpManager {
  static final HttpManager _instance = HttpManager._internal();
  factory HttpManager() => _instance;

  late Dio dio;

  HttpManager._internal() {
    // BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
    BaseOptions options = BaseOptions(
      // 请求基地址,可以包含子路径
      baseUrl: currentEnvironment.host,

      // baseUrl: storage.read(key: STORAGE_KEY_APIURL) ?? SERVICE_API_BASEURL,
      //连接服务器超时时间,单位是毫秒.
      connectTimeout: 10000,

      // 响应流上前后两次接受到数据的间隔,单位为毫秒。
      receiveTimeout: 5000,

      // Http请求头.
      headers: {},

      contentType: 'application/json; charset=utf-8',

      responseType: ResponseType.json,
    );

    dio = Dio(options);

  }

  /// restful get 操作
  Future get(
      String path, {
        dynamic? queryParameters,
        Options? options,
      }) async {
    var response = await dio.get(
      path,
      queryParameters: queryParameters,
      options: options,
    );
    print(response.data);
    return response.data;
  }
}

使用


RxList listData = [].obs;
Future<void> requestData() async {
 var response = await HttpManager().get('home/chat/list');
 List<dynamic> data = response['data'];
 listData.value =  data.map((e) => ChatModel.fromJson(e)).toList();
}

打印结果: image.png

4. 小结

Getx对我们的http请求做了封装,我们可以自定义其配置项,里面监听和拦截方法方便我们放些请求头设置或者自定义的操作,定义一个标准的解码器,该解码器将把您的所有请求转换为需要的模型,而不需要任何额外的配置。之后复值配合我们的Rx<T> 刷新页面。我们也可以使用Dio封装进行网络请求之后附值,刷新页面,响应式表达