client_base.dart 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import 'dart:convert';
  2. import 'package:dio/dio.dart' as dio;
  3. import 'package:fis_common/http/http_error.dart';
  4. import 'package:fis_jsonrpc/encrpyt.dart';
  5. import 'package:flutter/foundation.dart';
  6. import 'exception.dart';
  7. import 'http_pool.dart';
  8. import 'interceptor.dart';
  9. import 'request.dart';
  10. // ignore: unused_element
  11. const _C_DIO_FUTURE_ERR_MSG = "Future already completed";
  12. const _C_DIO_FUTURE_ERR_KEYWORDS = "browser_adapter";
  13. /// JSON-RPC Client 基类
  14. class JsonRpcClientBase {
  15. /// 默认超时时间
  16. // ignore: non_constant_identifier_names
  17. static int DEAULT_TIMEOUT = 15000;
  18. /// 请求加密配置
  19. static JsonRpcEncryptConfig requestEncryptConfig = JsonRpcEncryptConfig();
  20. /// 响应加密配置
  21. static JsonRpcEncryptConfig responseEncryptConfig = JsonRpcEncryptConfig();
  22. late int _timeout;
  23. late String _serviceName;
  24. /// 服务主机地址
  25. final String host;
  26. /// 自定义Http header
  27. final Map<String, String>? headers;
  28. /// 超时时间(ms)
  29. int get timeout => _timeout;
  30. /// 服务名称
  31. String get serviceName => _serviceName;
  32. /// 服务请求地址
  33. String get servicePath =>
  34. host.endsWith('/') ? "$host$serviceName" : "$host/$serviceName";
  35. JsonRpcClientBase(
  36. this.host,
  37. String serviceName, {
  38. this.headers,
  39. int? timeout,
  40. }) {
  41. _timeout = timeout ?? DEAULT_TIMEOUT;
  42. _serviceName = serviceName;
  43. }
  44. void setTimeout(int milliseconds) {}
  45. /// 设置服务名
  46. void setServiceName(String name) => _serviceName = name;
  47. /// 请求RPC method
  48. @protected
  49. Future<dynamic> call(String method, [args]) async {
  50. var request = JsonRpcRequest(method, args);
  51. return _transmit(request);
  52. }
  53. /// 通知 RPC method
  54. @protected
  55. void notify(String method, [args]) {
  56. var request = JsonRpcRequest(method, args, notify: true);
  57. _transmit(request);
  58. }
  59. Future<dynamic> _transmit(JsonRpcRequest request) async {
  60. var result;
  61. try {
  62. final req = await jsonRpcInterceptHost.onRequestTransmit(request);
  63. String package = jsonEncode(req.toJson());
  64. if (requestEncryptConfig.enable) {
  65. package = _encryptRequestPackage(package);
  66. }
  67. var response = await _postRequest(package);
  68. if (response == null) throw JsonRpcException(message: "Response Empty");
  69. if (response is String) {
  70. response = jsonDecode(response);
  71. }
  72. result = await _handleDecoded(response);
  73. } catch (e) {
  74. if (e is FHttpError)
  75. await _handleHttpRequestError(JsonRpcNetworkException(
  76. e.toString(),
  77. null,
  78. request.method,
  79. ));
  80. throw JsonRpcException(message: "Http error", data: e);
  81. }
  82. return result;
  83. }
  84. Future<dynamic> _postRequest(String package) async {
  85. try {
  86. final httpClient = jrpcHttpPool.getClient(
  87. this.host,
  88. timeout: this.timeout,
  89. headers: this.headers,
  90. );
  91. var response =
  92. await httpClient.post('/${this.serviceName}', data: package);
  93. if (response.statusCode != 200) {
  94. throw JsonRpcException(
  95. message: "Http error.Status coder: ${response.statusCode}.");
  96. }
  97. if (response.headers.containsKey("response_encrypt_mode")) {
  98. final resEncryptMode = response.headers["response_encrypt_mode"]!;
  99. // 解密响应包
  100. if (resEncryptMode.isNotEmpty && resEncryptMode.first.isNotEmpty) {
  101. final resPackage = _decryptResponsePackage(response.data);
  102. final resJsonMap = jsonDecode(resPackage);
  103. return resJsonMap;
  104. }
  105. }
  106. return response.data;
  107. } on dio.DioError catch (e) {
  108. throw JsonRpcException(message: "Http error", data: e);
  109. } on StateError catch (e) {
  110. if (e.message == _C_DIO_FUTURE_ERR_MSG) {
  111. if (e.stackTrace != null &&
  112. e.stackTrace.toString().contains(_C_DIO_FUTURE_ERR_KEYWORDS)) {
  113. // don't rethrow
  114. }
  115. }
  116. }
  117. }
  118. Future<dynamic> _handleHttpRequestError(JsonRpcNetworkException error) async {
  119. final res = await jsonRpcInterceptHost.onHttpRequestError(error);
  120. throw res;
  121. }
  122. Future<dynamic> _handleDecoded(Map<String, dynamic> response) async {
  123. final res = await jsonRpcInterceptHost.onResponse(response);
  124. if (res.containsKey('error')) {
  125. var error = JsonRpcServerError.fromJson(res['error']);
  126. error = await jsonRpcInterceptHost.onResponseError(error);
  127. throw error;
  128. }
  129. var result = res['result'];
  130. result = await jsonRpcInterceptHost.onResponseResult(result);
  131. return result;
  132. }
  133. String _encryptRequestPackage(String package) {
  134. final mode = requestEncryptConfig.encryptMode.toLowerCase();
  135. if (kIsWeb) {
  136. return package;
  137. }
  138. if (mode == "sm2") {
  139. // 使用国密2加密请求
  140. return JsonRpcEncryptUtils.sm2Encrypt(
  141. package,
  142. requestEncryptConfig.encryptKey,
  143. );
  144. }
  145. if (mode == "rsa") {
  146. // 使用RSA加密请求
  147. return JsonRpcEncryptUtils.rsaEncrypt(package);
  148. }
  149. return package;
  150. }
  151. String _decryptResponsePackage(String package) {
  152. final mode = responseEncryptConfig.encryptMode.toLowerCase();
  153. if (mode == "sm4") {
  154. // 使用国密4解密
  155. return JsonRpcEncryptUtils.sm4Decrypt(
  156. package,
  157. responseEncryptConfig.encryptKey,
  158. );
  159. }
  160. if (mode == "des") {
  161. // 使用DES解密
  162. // 截取前8位
  163. final key = responseEncryptConfig.encryptKey.substring(0, 8);
  164. return JsonRpcEncryptUtils.desDecrypt(package, key);
  165. }
  166. return package;
  167. }
  168. }
  169. abstract class JsonRpcRequestModelBase {
  170. /// 转成Json Map
  171. Map<String, dynamic> toJson();
  172. }