Flutter JSON-RPC通信插件jsonrpc2的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter JSON-RPC通信插件jsonrpc2的使用

jsonrpc2

此包是一组纯 Dart 工具类和方法,用于在 Dart 中实现 JSON-RPC 客户端和服务器。你需要提供实际的通信协议。文档、示例和测试均已提供。

JSON-RPC 是一种 JSON 编码语法,用于调用远程服务器上的方法并接收响应。该规范位于 https://jsonrpc.org

使用

JSON-RPC 被分为客户端和服务器的责任。此包实现了 JSON-RPC 2.0 规范中繁琐的部分,并为服务器提供了 1.0 的回退支持。

客户端

与规范一样,客户端实现不指定客户端的传输细节。需要创建一个从 ServerProxyBase 扩展的类,以实际发送方法请求并接收响应。请参阅示例以了解常见用法,或查看以下步骤说明。

实例化后,客户端代理可以使用代理的 call 方法调用服务器上的方法,并接收响应。客户端有责任匹配服务器的 API。

Future<dynamic> call(String method, [dynamic params])
  • proxy.call('method_a') // 没有参数
  • proxy.call('method_b', [arg1]) // 一个参数,通用情况
  • proxy.call('method_c', arg1) // 一个参数,参数既不是 [] 也不是 {}
  • proxy.call('method_d', [arg1, arg2, arg3]) // 多个参数
  • proxy.call('method_e', [[item1, item2, item3, item4]]) // 一个参数,参数是 []
  • proxy.call('method_f', [{'a': 'hello', 'b': 'world'}]) // 一个参数,参数是 {}
  • proxy.call('method_g', {'name_a':value_a,'name_b':value_b}) // 命名参数

创建一个客户端(ServerProxy)类

  1. 导入客户端库。
import 'package:jsonrpc2/jsonrpc2.dart';
import 'package:rpc_exceptions/rpc_exceptions.dart';
  1. 创建一个从 ServerProxyBase 扩展的服务器代理类,并初始化服务器资源。resource 可能在 transmit 方法中使用。
class MyServerProxy extends ServerProxyBase {
  /// 构造函数。如果你想要扩展它,请正确地使用 `super`
  MyServerProxy(resource) // resource 可以是任何东西
      : super(resource);
}
  1. 在你的服务器代理类中重写 transmit 方法,该方法发送一个字符串到远程 JSON-RPC 服务器并返回返回的字符串。你可以使用之前标识的服务器资源。
/// 返回一个包含 JSON-RPC 响应的 Future。使用真实的传输方式,
/// 如 `package:http` 而不是虚构的 `ExampleTransport`。
  @override
  Future<String> transmit(String package) async {

    // 例如,使用字符串资源名称创建一个传输对象。
    var transport = ExampleTransport(resource);

    // 使用传输发送包,并等待响应
    var response = await transport.send(package);

    // 返回字符串响应以进行进一步处理
    return response;
  }
  1. 使用你的服务器代理实例来调用该端点上的方法,并处理结果。
/// 获取服务器列表中紧跟在该项目后面的那个项目
MyViewItem nextItem (String lastItemId) async {
  var remoteSite = MyServerProxy('https://example.org/');
  
  var item = await remoteSite.call('nextItem', lastItemId);
  // 或者,如果你在代理中镜像了服务器 API,
  // var nextItem = await remoteSite.nextItem(lastItemId);  // 非常好!
  return MyViewItem.fromJson(item);
}

示例 JSON-RPC 客户端使用 http.dart 来自 pub.dev

// 使用 http.dart 包的 JSON-RPC 客户端
import 'package:http/http.dart' as http;

class HttpServerProxy extends ServerProxyBase {
  final String url;

  HttpServerProxy(this.url);

  @override
  Future<String> transmit(String package) async {
    var response = await http.post(
      Uri.parse(url),
      headers: {"Content-Type": "application/json"},
      body: package,
    );
    return response.body;
  }
}

客户端通知

JSON-RPC 支持通知的概念。通知是一种在不期望响应的情况下调用远程服务器上的方法的方式。

通过使用 notify 而不是 call 来调用客户端(或服务器代理)上的远程方法。

void notify(String method, [dynamic params])

JSON-RPC 规范要求通知没有响应。一些传输方式,如 HTTP,总是返回响应。你可以在服务器代理的覆盖 transmit 方法中适当地处理这种情况。对于 HTTP,我的示例从服务器返回空字符串或 204 状态码,而服务器代理返回空字符串。无论如何,ServerProxyBasenotify 方法不会返回任何内容。

批量请求

JSON-RPC V2 支持将多个方法请求批量到一个传输请求中。

为了在客户端上支持这一点,在创建你的客户端(服务器代理)类之后,执行以下操作:

  1. 使用你的客户端 ServerProxy 类作为实例代理创建一个客户端 BatchServerProxy 类。
/// 查看 [BatchServerProxyBase] 文档
class MyBatchServerProxy extends BatchServerProxyBase {
  @override
  dynamic proxy;

  /// 构造函数
  MyBatchServerProxy(String url, [customHeaders = const <String, String>{}]) {
    proxy = MyServerProxy(url, customHeaders);
  }
}
  1. 使用你的 BatchServerProxy 类,像使用普通代理一样调用任意数量的方法。然后作为批处理发送这些方法。
/// 调用一些方法以返回三个项目
List threeItems () async {
  var remoteSite = MyBatchServerProxy('https://example.org/');
  
  var item1 = remoteSite.call('firstItem');
  var item2 = remoteSite.call('secondItem');
  remoteSite.notify('happyLog', 'I hope the last item comes through!');
  var item3 = remoteSite.call('lastItem');
  // 或者,如果你在代理中镜像了服务器 API,
  // var item1 = remoteSite.item1();  // ...等等。

  // 现在,向服务器发送请求。
  await remoteSite.send();

  // 现在处理来自调用的 Futures。
  return [fromJson(await item1), fromJson(await item2), fromJson(await item3)]
}

服务器基础

服务器库解码 JSON-RPC 请求包,并允许将 JSON-RPC 请求与调用远程方法的对象关联起来,并返回结果。网络和传输问题不在此实现的范围内。也就是说,这设计得相当容易与你使用的传输或框架一起使用。这只是使用调度器的一个方法。在服务器实现中,为特定调度器创建一个端点,并使用这些工具解码请求并打包结果。

此服务器实现使用调度器概念。本质上,调度器是一个包含要在一个端点上调用的远程方法的实例化的类。服务器接受一个调用请求,解构 JSON,然后创建或关联一个调度器以调用该实例上的方法,使用请求的参数。返回值(或异常)被组装成一个 JSON 响应并发送回客户端。

  • 导入服务器库
import 'package:jsonrpc2/jsonrpc2.dart';
  • 创建一个实现端点服务方法的类。几乎任何带有方法的类都可以。example/api_class.dart,如果在不同的文件中,导入它。
import 'rpc_methods.dart';
  • 为您的监听器创建一个方法,该方法接受来自客户端的 JSON-RPC 字符串。这个字符串可能,例如,是 HTTP POST 的主体。在这个方法内,使用这个库的 jsonRpc 方法将字符串与 Dispatcher 关联起来,后者执行方法。jsonRpc 方法最终会生成一个字符串,应该将其作为响应发送回客户端。

jsonRpc 方法具有以下签名。

Future<String> jsonRpc(String request, Dispatcher dispatcher)
  • request 是来自客户端的 JSON-RPC 请求字符串。

  • dispatcher 满足 Dispatcher 接口。你会想要使用以下之一:

    • mirror_dispatcher
    • reflector_dispatcher

这两个实现等效工作。mirror_dispatcher 更易于使用,但它使用 dart:mirrors,不能在 Flutter 应用程序中使用。可能还有其他权衡。

示例服务器使用 shelf_iomirror_dispatcher

import 'package:jsonrpc2/jsonrpc2.dart';
import 'package:mirror_dispatcher/mirror_dispatcher.dart';

class MyService {
  String firstMethod() => "Hello, World!";
}

void main() {
  var dispatcher = new MethodMirrorDispatcher(MyService());
  var handler = createHandler(dispatcher);
  runServer(handler);
}

示例服务器使用 shelf_ioreflector_dispatcher

import 'package:jsonrpc2/jsonrpc2.dart';
import 'package:reflector_dispatcher/reflector_dispatcher.dart';

class MyService {
  String firstMethod() => "Hello, World!";
}

void main() {
  var dispatcher = new ReflectorDispatcher(MyService());
  var handler = createHandler(dispatcher);
  runServer(handler);
}

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

1 回复

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


在Flutter中,使用jsonrpc2插件进行JSON-RPC通信可以让我们与基于JSON-RPC协议的服务器进行交互。以下是一个简单的示例,展示了如何在Flutter项目中使用jsonrpc2插件来进行JSON-RPC通信。

首先,确保你的Flutter项目中已经添加了jsonrpc2依赖。在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  jsonrpc2: ^3.0.0  # 请根据最新版本调整版本号

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

接下来,我们编写一个Flutter应用,它使用jsonrpc2客户端与JSON-RPC服务器进行通信。假设我们有一个JSON-RPC服务器运行在http://localhost:8545(这通常是以太坊JSON-RPC节点的默认地址,但你可以根据实际情况替换)。

以下是一个简单的Flutter应用示例:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:jsonrpc2/jsonrpc2.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter JSON-RPC Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String responseText = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter JSON-RPC Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Response:',
            ),
            Text(
              responseText,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                await sendRpcRequest();
              },
              child: Text('Send RPC Request'),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> sendRpcRequest() async {
    final client = JsonRpcClient(
      'http://localhost:8545',
      client: http.Client(),
    );

    try {
      final request = Request('web3_clientVersion', []);
      final response = await client.send(request);
      
      if (response is SuccessResponse) {
        setState(() {
          responseText = 'Client Version: ${response.result}';
        });
      } else if (response is ErrorResponse) {
        setState(() {
          responseText = 'Error: ${response.error.message} (code: ${response.error.code})';
        });
      }
    } catch (e) {
      setState(() {
        responseText = 'Exception: $e';
      });
    } finally {
      client.close();
    }
  }
}

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

  1. 添加依赖:在pubspec.yaml文件中添加了jsonrpc2依赖。
  2. 创建Flutter应用:使用MaterialAppScaffold等Flutter组件创建了一个简单的UI。
  3. 定义RPC客户端:在sendRpcRequest方法中,我们创建了一个JsonRpcClient实例,用于与JSON-RPC服务器通信。
  4. 发送RPC请求:构造了一个Request对象,并使用client.send(request)方法发送请求。然后,我们根据响应的类型(SuccessResponseErrorResponse)更新UI。
  5. 处理异常和关闭客户端:在try-catch块中处理可能的异常,并在finally块中关闭客户端连接。

这个示例展示了如何使用jsonrpc2插件在Flutter中与JSON-RPC服务器进行基本的通信。你可以根据需要扩展这个示例,以处理更多的RPC方法和复杂的请求/响应结构。

回到顶部