Flutter插件gio的使用方法

Flutter插件gio的使用方法

这是来自Dart的一个强大的HTTP请求库。它具有链式调用拦截器,通过它可以实现许多功能。

例如,它提供了一个拦截器来模拟后端响应。这允许我们快速构建和调试UI而不依赖于后端开发人员的进度。

Flutter插件gio的使用

快速开始

pubspec.yaml文件中添加依赖:

dependencies:
  gio: latest

使用示例代码:

import 'dart:convert';

import 'package:gio/gio.dart' as gio;

void main() async {
  var resp =
      await gio.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
  print(resp.body);

  /// GET http://example.com?a=1&b=2
  resp = await gio.get("http://example.com", queryParameters: {"a": "1", "b": "2"});
  print(resp.request?.url);

  /// POST 表单数据
  var data = {"username": "Bob", "passwd": "123456"};
  var header = {"content-type": "application/x-www-form-urlencoded"};
  resp = await gio.post("http://example.com", headers: header, body: data);
  print(resp.body);

  /// POST JSON 数据
  /// 注意:如果传递JSON数据,
  /// 则body应该是一个字符串类型
  var data2 = {"name": "Bob", "age": "22"};
  var header2 = {"content-type": "application/json"};
  resp = await gio.post("http://example.com", headers: header, body: jsonEncode(data));
  print(resp.body);
}

你也可以像以下方式使用Gio,在连接关闭之前可以重用此连接:

import 'package:gio/gio.dart';

void main() async {
  Gio gio = Gio();
  try {
    var resp = await gio.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(resp.body);
  } finally {
    gio.close();
  }
}

全局配置

我们可以使用GioOption设置全局基础URL:

import 'package:gio/gio.dart' as gio;

void main() async {
  gio.Gio.option = gio.GioOption(
      basePath: 'https://giomock.io',
      enableLog: true
  );

  // 等同于 https://giomock.io/greet
  var resp = await gio.get("/greet", queryParameters: {'name': 'Bob'});
  print(resp.body);
}

enableLog设置为true以启用全局日志,便于跟踪请求。

注意,如果你在GioOption中配置了basePath,但在某些请求中没有应用这个basePath,则需要在请求中覆盖此参数,如下所示:

import 'package:gio/gio.dart';

void main() async {
  Gio.option = GioOption(
      basePath: 'https://giomock.io',
      enableLog: true
  );

  // 将Gio的baseUrl设置为空字符串
  // 以覆盖全局配置
  Gio gio = Gio(baseUrl: '');
  try {
    var resp = await gio.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(resp.body);
  } finally {
    gio.close();
  }
}

拦截器

拦截器类型,即匹配以下签名的函数或闭包:

typedef Interceptor = Future<StreamedResponse> Function(Chain chain);

Gio拦截器分为三种类型:

  • 全局拦截器
  • 本地拦截器
  • 默认拦截器

注意,这三种类型的拦截器中,本地拦截器首先被调用,然后是全局拦截器,最后是默认拦截器。

全局拦截器

全局拦截器是全局有效的,通过GioOption设置:

void main() async {
  // 声明一个拦截器
  checkHeader(gio.Chain chain) {
    var auth = chain.request.headers['Authorization'];
    // 当条件满足时,继续执行下一个拦截器,
    // 否则中断请求
    if (auth != null && auth.isNotEmpty) {
      return chain.proceed(chain.request);
    }
    throw Exception('无效请求,不包含Authorization!');
  }

  // 参数是一个列表,可以设置多个拦截器
  gio.Gio.option = gio.GioOption(
      basePath: 'http://worldtimeapi.org',
      globalInterceptors: [checkHeader]);

  try {
    var resp = await gio.get("/api/timezone/Asia/Shanghai");
    print(resp.body);
  } catch (e) {
    print(e);
  }
}

输出结果:

Exception: 无效请求,不包含Authorization!

Process finished with exit code 0
本地拦截器

本地拦截器也可以添加多个:

import 'package:gio/gio.dart';

void main() async {
  Gio gio = Gio();

  // 拦截请求并修改请求头
  gio.addInterceptor((chain) {
    if (chain.request.method == "POST") {
      chain.request.headers["content-type"] = "application/json";
    }
    return chain.proceed(chain.request);
  });

  // 拦截响应并在其中进行一些业务处理
  gio.addInterceptor((chain) async {
    var res = await chain.proceed(chain.request);
    if (res.statusCode != 200) {
      throw Exception(
          "请求失败,状态码为 ${res.statusCode}");
    }
    return res;
  });

  try {
    var resp = await gio.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(resp.body);
  } catch (e) {
    print(e);
  } finally {
    gio.close();
  }
}

我们还可以将拦截器逻辑放入类中而不是闭包,这可以更好地组织我们的代码。

这里我们实现一个取消请求的例子,当用户离开视图时,请求的结果可能不再需要:

cancel_interceptor.dart

import 'package:gio/gio.dart';

class CancelInterceptor {
  bool _isCancel = false;

  void cancel() {
    _isCancel = true;
  }

  Future<StreamedResponse> call(Chain chain) async {
    if (_isCancel) {
      throw CancelError("用户发起取消。");
    }
    var res = await chain.proceed(chain.request);
    if (_isCancel) {
      throw CancelError("用户发起取消。");
    }
    return res;
  }
}

main.dart

import 'package:gio/gio.dart';

void main() {
  var cancelInterceptor = CancelInterceptor();
  testCancel(cancelInterceptor);
  cancelInterceptor.cancel();
}

Future<void> testCancel(CancelInterceptor cancel) async {
  Gio g = Gio();
  g.addInterceptor(cancel);
  try {
    var res = await g.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(res.body);
  } on CancelError {
    print("请求已被取消");
  } finally {
    g.close();
  }
}
组拦截器

拦截器允许我们使用统一的方式来处理网络请求,但有时我们可能需要基于模块自定义网络请求。组拦截器用于这种情况。

import 'package:gio/gio.dart' as gio;

void main() async {
  // 设置组拦截器
  gio.group("module1").addInterceptor(CancelInterceptor());
  gio.group("module2").addInterceptor(ModifyHeaderInterceptor());

  var module1 = gio.GioGroup("module1");
  try {
    var resp = module1.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(resp);
  } catch (e) {
    print(e);
  } finally {
    module1.close();
  }

  var module2 = gio.GioGroup("module2");
  try {
    var resp = module2.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(resp);
  } catch (e) {
    print(e);
  } finally {
    module2.close();
  }
}
默认拦截器

默认拦截器是指在GioOption中包含的几个拦截器,它们是:

  • GioLogInterceptor
  • GioConnectInterceptor
  • GioMockInterceptor

我们可以自定义这些拦截器来替换默认拦截器:

import 'package:gio/gio.dart';

void main() async {
  Gio.option = GioOption(
    connectInterceptor: MyConnectInterceptor(),
    logInterceptor: MyLogInterceptor()
  );

  Gio gio = Gio();
  try {
    var resp = await gio.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai");
    print(resp.body);
  } finally {
    gio.close();
  }
}

class MyConnectInterceptor extends GioConnectInterceptor {

  [@override](/user/override)
  Future<bool> checkConnectivity() {
    // TODO: 在此处检查当前网络是否已连接
    throw ConnectiveError(101, "移动网络数据已禁用!");
    // 或
    // throw ConnectiveError(102, "WiFi已禁用!");
  }
}

class MyLogInterceptor extends GioLogInterceptor {
  [@override](/user/override)
  Future<StreamedResponse> call(Chain chain) async {
    final request = chain.request;
    // _logRequest(request);
    try {
      final response = await chain.proceed(request);
      // _logResponse(response);
      return response;
    } catch (e) {
      // _logUnknownError(e, request);
      rethrow;
    }
  }
}

注意,默认拦截器也是全局可用的。

在这里,我们可以在拦截器中实现日志跟踪和请求耗时监控。你可以参考GioLogInterceptor的源代码:

// 参考源代码:https://github.com/arcticfox1919/gio/blob/main/gio/lib/src/interceptor/log_interceptor.dart

模拟响应

模拟响应是在你想要先开发UI或在没有服务后端的情况下测试和调试UI时非常有用的功能。

pubspec.yaml文件中添加依赖:

dependencies:
  gio: latest
  gio_mock: latest

要使用模拟后端响应的功能,你需要设置mockInterceptor参数,如示例所示:

void main() async {
  gio.Gio.option = gio.GioOption(
      basePath: 'https://giomock.io',
      mockInterceptor: GioMockServer(MyMockChannel()));

  var resp = await gio.get("/greet", queryParameters: {'name': 'Bob'});
  print(resp.body);

  var data = {"username": "Bob", "passwd": "123456"};
  var header = {"content-type": "application/x-www-form-urlencoded"};
  resp = await gio.post("/login", headers: header, body: data);
  print(resp.body);

  var data2 = {
    "array": [
      {
        "name": "Go",
        "url": "https://go.dev/"
      },
      {
        "name": "Dart",
        "url": "https://dart.dev/"
      },
    ]
  };
  header = {"content-type": "application/json"};
  resp = await gio.post("/list", headers: header, body: jsonEncode(data2));
  print(resp.body);
}

接下来,你需要创建MyMockChannel

import 'package:gio_mock/gio_mock.dart';
import 'package:gio_mock/src/http/response_x.dart';

class MyMockChannel extends MockChannel {

  [@override](/user/override)
  void entryPoint() {
    get("/greet", (MockRequest request) {
      return ResponseX.ok("hello,${request.query['name']}");
    });

    post("/login", (MockRequest request) {
      return ResponseX.ok(request.bodyFields);
    });

    post("/list", (MockRequest request) {
      return ResponseX.ok(request.body);
    });
  }
}

更多关于Flutter插件gio的使用方法的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter插件gio的使用方法的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,有时候我们会遇到一些插件,其官方文档或介绍不够详尽,甚至是“undefined”状态。尽管我们不清楚其具体功能,但基于Flutter插件的一般使用方式,我们可以尝试导入并使用该插件。以下是一个关于如何使用名为gio的Flutter未知功能插件的示例代码框架。

首先,确保你已经在pubspec.yaml文件中添加了该插件的依赖项。由于我们不知道具体的版本号,这里假设最新版本为latest_version(你需要替换为实际可用的版本号):

dependencies:
  flutter:
    sdk: flutter
  gio: ^latest_version  # 替换为实际版本号

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

接下来,在你的Dart代码中导入该插件:

import 'package:gio/gio.dart';

由于我们不知道gio插件的具体功能,我们将尝试一些常见的插件使用模式。以下是一个基本的示例,假设gio有一个初始化函数和一个可能的事件监听器:

import 'package:flutter/material.dart';
import 'package:gio/gio.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: GioExamplePage(),
    );
  }
}

class GioExamplePage extends StatefulWidget {
  @override
  _GioExamplePageState createState() => _GioExamplePageState();
}

class _GioExamplePageState extends State<GioExamplePage> {
  // 假设gio有一个初始化方法initGio
  // 和一个事件监听器,例如onGioEvent
  Gio? _gioInstance;

  @override
  void initState() {
    super.initState();
    // 初始化gio插件
    _initGio();
  }

  void _initGio() async {
    // 假设initGio是一个异步方法
    _gioInstance = await Gio.init(); // 根据实际情况调整方法名和参数

    // 设置事件监听器
    _gioInstance?.onGioEvent?.listen((event) {
      // 处理事件
      print('Received event from gio: $event');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gio Example'),
      ),
      body: Center(
        child: Text('Waiting for gio to initialize...'),
      ),
    );
  }

  @override
  void dispose() {
    // 清理资源
    _gioInstance?.onGioEvent?.cancel();
    super.dispose();
  }
}

在这个示例中,我们做了以下几件事:

  1. pubspec.yaml中添加了gio插件的依赖。
  2. 在Dart代码中导入了gio插件。
  3. 创建了一个Flutter应用,其中包含一个尝试初始化gio插件并设置事件监听器的页面。

请注意,由于gio插件的具体功能和API未知,上述代码中的Gio.init()_gioInstance?.onGioEvent等假设方法名和事件监听器是基于一般插件使用模式的推测。在实际使用中,你需要根据gio插件的实际文档或源代码来调整这些部分。

如果gio插件没有提供足够的文档或示例代码,你可能需要查看其源代码或联系插件的维护者以获取更多信息。

回到顶部