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

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

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

json_rpc_2 是一个实现了 JSON-RPC 2.0 规范的Dart库。它使得在Flutter应用程序中实现客户端-服务器架构变得简单,特别是在需要通过WebSocket进行实时通信时。

安装

首先,在你的 pubspec.yaml 文件中添加依赖:

dependencies:
  json_rpc_2: ^3.0.0
  web_socket_channel: ^2.0.0

然后运行 flutter pub get 来安装这些包。

示例项目

下面是一个完整的示例项目,展示了如何创建一个JSON-RPC服务器和客户端,并通过WebSocket进行通信。

服务器端代码

服务器端代码创建了一个HTTP服务器,监听本地4321端口,并处理来自客户端的请求。每个连接都被转换为WebSocket连接,然后注册一些方法供客户端调用。

import 'dart:io';

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() async {
  var httpServer = await HttpServer.bind(InternetAddress.loopbackIPv4, 4321);
  print('Listening on ws://${httpServer.address.address}:${httpServer.port}');
  
  var connectedChannels =
      httpServer.transform(WebSocketTransformer()).map(IOWebSocketChannel.new);
  connectedChannels.listen(handleClient);
}

void handleClient(WebSocketChannel socket) {
  // The socket is a `StreamChannel<dynamic>` because it might emit binary
  // `List<int>`, but JSON RPC 2 only works with Strings so we assert it only
  // emits those by casting it.
  var server = Server(socket.cast<String>());

  // Any string may be used as a method name. JSON-RPC 2.0 methods are
  // case-sensitive.
  var i = 0;
  server.registerMethod('count', () {
    return i++;
  });

  // Methods can take parameters. They're presented as a `Parameters` object
  // which makes it easy to validate that the expected parameters exist.
  server.registerMethod('echo', (Parameters params) {
    return params['message'].value;
  });

  // `Parameters` has methods for verifying argument types.
  server.registerMethod('subtract', (Parameters params) {
    return params['minuend'].asNum - params['subtrahend'].asNum;
  });

  // [Parameters] also supports optional arguments.
  server.registerMethod('sort', (Parameters params) {
    var list = params['list'].asList;
    list.sort();
    if (params['descending'].asBoolOr(false)) {
      return list.reversed.toList();
    } else {
      return list;
    }
  });

  // A method can send an error response by throwing a `RpcException`.
  const divideByZero = 1;
  server.registerMethod('divide', (Parameters params) {
    var divisor = params['divisor'].asNum;
    if (divisor == 0) {
      throw RpcException(divideByZero, 'Cannot divide by zero.');
    }

    return params['dividend'].asNum / divisor;
  });

  // To give you time to register all your methods, the server won't start
  // listening for requests until you call `listen`. Messages are buffered until
  // listen is called. The returned Future won't complete until the connection
  // is closed.
  server.listen();
}

客户端代码

客户端代码连接到服务器并调用服务器上定义的方法。它演示了如何发送带参数的请求、处理响应以及捕获错误。

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:pedantic/pedantic.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() async {
  var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));
  var client = Client(socket.cast<String>());

  // The client won't subscribe to the input stream until you call `listen`.
  unawaited(client.listen());

  try {
    // This calls the "count" method on the server. A Future is returned that
    // will complete to the value contained in the server's response.
    var count = await client.sendRequest('count');
    print('Count is $count');

    // Parameters are passed as a simple Map or, for positional parameters, an
    // Iterable. Make sure they're JSON-serializable!
    var echo = await client.sendRequest('echo', {'message': 'hello'});
    print('Echo says "$echo"!');

    // A notification is a way to call a method that tells the server that no
    // result is expected. Its return type is `void`; even if it causes an
    // error, you won't hear back.
    client.sendNotification('count');

    // If the server sends an error response, the returned Future will complete
    // with an RpcException. You can catch this error and inspect its error
    // code, message, and any data that the server sent along with it.
    try {
      await client.sendRequest('divide', {'dividend': 2, 'divisor': 0});
    } on RpcException catch (error) {
      print('RPC error ${error.code}: ${error.message}');
    }

    // Call sort method with descending order
    var sortedList = await client.sendRequest('sort', {'list': [3, 1, 2], 'descending': true});
    print('Sorted list: $sortedList');
  } finally {
    await client.close();
  }
}

总结

以上代码展示了如何在Flutter应用中使用 json_rpc_2 插件来实现JSON-RPC通信。通过WebSocket连接,你可以轻松地构建出高效的客户端-服务器交互模型。希望这个例子能帮助你更好地理解和使用 json_rpc_2 插件!如果你有任何问题或需要进一步的帮助,请随时提问。


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

1 回复

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


当然,下面是一个关于如何在Flutter项目中使用json_rpc_2插件进行JSON-RPC通信的示例代码。这个示例展示了如何设置一个基本的JSON-RPC客户端和服务器通信。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加json_rpc_2的依赖:

dependencies:
  flutter:
    sdk: flutter
  json_rpc_2: ^2.2.3  # 确保使用最新版本

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

2. 创建JSON-RPC服务器(例如在Dart VM中运行)

为了演示,我们创建一个简单的Dart VM应用程序作为JSON-RPC服务器。

// server.dart
import 'dart:io';
import 'package:json_rpc_2/json_rpc_2.dart';

void main() async {
  HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8080);
  print('Listening on http://localhost:8080');

  server.listen((HttpRequest request) async {
    if (request.method == 'POST') {
      var jsonRpc = new Peer(request.reader);
      var response = await jsonRpc.receive();

      if (response is Request) {
        Request req = response as Request;
        if (req.method == 'sum') {
          // 假设sum方法接受两个整数参数并返回它们的和
          int a = req.params['a'] as int;
          int b = req.params['b'] as int;
          var result = new Success(result: a + b);
          await jsonRpc.send(result);
        } else {
          await jsonRpc.send(new Error(-32601, 'Method not found'));
        }
      } else {
        // 处理其他类型的响应
      }

      await request.response.close();
    } else {
      request.response
        ..statusCode = HttpStatus.methodNotAllowed
        ..close();
    }
  });
}

3. 创建Flutter客户端

接下来,我们在Flutter项目中创建一个JSON-RPC客户端来与服务器通信。

// main.dart
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:json_rpc_2/json_rpc_2.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter JSON-RPC Demo',
      home: RpcDemo(),
    );
  }
}

class RpcDemo extends StatefulWidget {
  @override
  _RpcDemoState createState() => _RpcDemoState();
}

class _RpcDemoState extends State<RpcDemo> {
  String result = '';

  void _sendRpcRequest() async {
    var client = new http.Client();
    var body = jsonEncode(Request(
      id: '1',
      jsonrpc: '2.0',
      method: 'sum',
      params: {'a': 10, 'b': 20}
    ).toJson());

    var response = await client.post(
      Uri.parse('http://localhost:8080'),
      body: Body.fromJson(Map.fromEntries(
        [MapEntry('content-type', 'application/json')].map((k, v) => MapEntry(k, v.toString()))
      )..addAll(body.bytes.map((byte) => MapEntry("${byte.toRadixString(16).padStart(2, '0')}", byte.toRadixString(16)))),
      headers: {
        'Content-Type': 'application/json',
      }
    );

    var responseBody = await response.body.decodeString();
    var rpcResponse = Response.fromJson(jsonDecode(responseBody));

    if (rpcResponse is Success) {
      setState(() {
        result = 'Result: ${(rpcResponse as Success).result}';
      });
    } else {
      setState(() {
        result = 'Error: ${(rpcResponse as Error).message}';
      });
    }

    client.close();
  }

  @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(
              'RPC Result:',
            ),
            Text(
              result,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _sendRpcRequest,
              child: Text('Send RPC Request'),
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

  1. 服务器运行:确保你的Dart VM服务器在Flutter客户端尝试连接之前已经启动。
  2. 跨域问题:如果你在Flutter应用中遇到跨域请求问题(CORS),你可能需要在服务器上配置CORS策略。
  3. 依赖版本:确保你使用的json_rpc_2版本是最新的,或者至少是与示例代码兼容的版本。

这个示例展示了如何使用json_rpc_2在Flutter应用中与Dart VM服务器进行基本的JSON-RPC通信。你可以根据需要扩展和修改这个示例。

回到顶部