Python-JsonRPC

发布于:2025-05-08 ⋅ 阅读:(19) ⋅ 点赞:(0)

Python-JsonRPC

使用Python学习JsonRPC数据交互


1-核心知识点

  • 1)什么是JsonRPC,这种协议是如何工作的?->使用请求进行验证
  • 2)JsonRPC可以使用Postman进行验证吗?->可以使用POSTMAN进行调用(使用HTTP请求即可)
  • 3)gRPC和jsonRPC对比->jsonRPC更早也更轻量级但是性能不高

2-思路整理

  • 1)JsonRPC也可以编写服务器进行约定参数传递
  • 2)但是JsonRPC性能不高

3-参考网址


4-动手实践

1-初始化环境

mkdir my_project
cd my_project
python -m venv .venv

2-激活环境

# Windows
source .venv/Scripts/activate

# Mac
source .venv/bin/activate

3-添加依赖

对应的依赖是在激活的环境中

pip install flask requests

4-创建JsonRPC服务端

from flask import Flask, request, jsonify
import json

app = Flask(__name__)

# 注册支持的 RPC 方法到字典
rpc_methods = {}

def register_rpc(method_name):
    """装饰器:注册一个 RPC 方法"""
    def decorator(func):
        rpc_methods[method_name] = func
        return func
    return decorator

@app.route('/rpc', methods=['POST'])
def rpc_handler():
    """处理 JSON-RPC 请求"""
    data = request.get_json()
    
    # 验证请求格式
    if not data or data.get('jsonrpc') != '2.0':
        return jsonify({
            'jsonrpc': '2.0',
            'id': None,
            'error': {
                'code': -32600,
                'message': 'Invalid Request'
            }
        }), 400

    method = data.get('method')
    params = data.get('params', [])
    _id = data.get('id')

    # 调用对应方法
    if method in rpc_methods:
        try:
            # 根据参数类型确定调用方式:数组参数 vs 对象参数
            if isinstance(params, list):
                result = rpc_methods[method](*params)
            elif isinstance(params, dict):
                result = rpc_methods[method](**params)
            else:
                raise TypeError("Parameters must be list or object")
            
            return jsonify({
                'jsonrpc': '2.0',
                'id': _id,
                'result': result
            })
        except Exception as e:
            return jsonify({
                'jsonrpc': '2.0',
                'id': _id,
                'error': {
                    'code': -32603,
                    'message': 'Internal error',
                    'data': str(e)
                }
            }), 500
    else:
        return jsonify({
            'jsonrpc': '2.0',
            'id': _id,
            'error': {
                'code': -32601,
                'message': 'Method not found'
            }
        }), 404

# 注册示例 RPC 方法

@register_rpc('add')
def add(a: int, b: int):
    """两个数相加"""
    return a + b

@register_rpc('subtract')
def subtract(minuend: int, subtrahend: int):
    """两个数相减"""
    return minuend - subtrahahend  # 故意写错拼写,演示错误处理

if __name__ == '__main__':
    app.run(port=5000)

5-验证JsonRPC服务

当前直接运行Python验证脚本

python test_rpc.py

# 1-测试加法->成功请求,返回3
Test 'add': {'id': 1, 'jsonrpc': '2.0', 'result': 3}

# 2-测试乘法->(因为没有定义)失败请求,返回Method not found
Test 'multiply': {'error': {'code': -32601, 'message': 'Method not found'}, 'id': 1, 'jsonrpc': '2.0'}

# 3-测试减法->(因为语法错误)失败请求,返回subtrahahend is not defined
Test 'subtract': {'error': {'code': -32603, 'data': "name 'subtrahahend' is not defined", 'message': 'Internal error'}, 'id': 1, 'jsonrpc': '2.0'}
  • 服务器接收请求参数

  • 执行验证脚本

6-Postman验证

  • POST请求数据


5-核心逻辑

1-主要代码解析

1-服务端核心逻辑
  1. 可用方法注册

    • 通过装饰器 @register_rpc('method_name') 将函数注册为可用的 RPC 方法。
  2. 请求处理

    • 检查必需字段(jsonrpcmethodid)。
    • 根据参数类型(列表或字典)分别解析参数:
      if isinstance(params, list):
          result = method(*params)
      elif isinstance(params, dict):
          result = method(**params)
      
  3. 错误处理

    • 内部错误返回 code=-32603
    • 方法未找到返回 code=-32601
    • 不符合请求格式时返回 code=-32600
2-客户端核心逻辑
  • 构造标准的 JSON-RPC 请求对象
  • 发送 POST 请求并接收响应
  • 根据返回的 id 和结果/错误信息进行处理

2-扩展说明

  1. 更复杂的错误处理
    服务端可以在错误对象中添加更多信息(如 data 字段):

    "error": {
        "code": -32000,
        "message": "Division by zero",
        "data": "Denominator is zero"
    }
    
  2. 支持变量请求ID
    可以让 id 动态生成:

    import uuid
    payload['id'] = str(uuid.uuid4())
    
  3. 支持批量请求
    服务端可以处理包含多个 RPC 请求的数组,客户端修改请求格式:

    payloads = [
        {"jsonrpc": "2.0", "method": "add", "params": [1,2], "id": 1},
        {"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 5, "subtrahend":3 }, "id": 2}
    ]
    
    response = requests.post(f"{base_url}/rpc", json=payloads)
    

3-使用场景说明

  • 为什么选择 Flask?
    • 易于搭建简单服务(3分钟内可启动服务端)
    • 适合快速开发原型系统
    • 支持 HTTP/HTTPS,默认兼容 JSON 格式
  • 为什么选择 requests?
    • Python 标准库函数支持构建 JSON 请求
    • 轻量级,不需要额外配置即可发送 HTTP 请求

4-其他实现方式

如果需要一个更完整的 JSON-RPC 库,可以使用:

  • jsonrpclib(Python2和Python3都支持,基于HTTP的简单库)
  • aiohttp_json_rpc(支持异步的 Python3 高级库)

6-补充说明

gRPC 和 JSON-RPC 都是远程过程调用(RPC)框架,用于服务之间的通信,但在通信协议性能序列化方式等方面存在显著差异。以下是两者的对比分析:


1. 基本概念

gRPC
  • 定义:由 Google 开发的高性能、开源、通用 RPC 框架,基于 Protocol Buffers(一种二进制序列化协议)和 HTTP/2 协议。
  • 设计目标:提供高性能、低延迟的通信,适用于分布式系统和微服务架构。
  • 特性
    • 支持 HTTP/2(支持双向流、多路复用、服务器推送)。
    • 支持多种语言(如 Java、Python、Go、C++ 等)。
    • 原生支持流式(流-流、流-单、单-流)通信。
    • 需通过 .proto 文件定义接口(接口描述语言,IDL)。
JSON-RPC
  • 定义:基于 JSON 的轻量级 RPC 协议,最早在 2005 年提出。
  • 设计目标:提供简单、灵活的远程调用,通常用于 Web 应用或轻量级服务间通信。
  • 特性
    • 通常基于 HTTP/1.1 或 TCP 传输层。
    • 使用 JSON 格式序列化数据(文本格式,可读性强)。
    • 支持同步和异步调用(具体实现依赖客户端/服务器)。
    • 无接口定义语言(IDL),接口需通过契约或文档约定。

2. 核心差异对比

特性 gRPC JSON-RPC
协议基础 HTTP/2 + Protocol Buffers HTTP/1.1 或 TCP + JSON
序列化格式 Binary(Protocol Buffers) → 效率高 JSON(文本格式) → 可读性好,但较冗余
性能与效率 高性能(二进制、HTTP/2、流式支持) 较低(文本 JSON 的解析开销和 HTTP/1.1 的头部开销)
语言支持 官方支持多种语言(Java、Go、Python等) 主流语言均有实现,依赖社区支持
流式通信 双向流(客户端-服务端双向实时通信) 基本不支持(需借助 WebSocket 等扩展)
接口定义(IDL) 需通过 .proto 文件定义接口 无正统 IDL,需通过文档或 JSON Schema 约定
传输层特性 HTTP/2(多路复用、二进制帧) HTTP/1.1(文本请求头、每请求一次连接)
错误处理 基于 Status 对象和 HTTP 状态码 遵循 JSON-RPC 标准的错误对象格式
部署复杂度 略高(需配置 HTTP/2,且依赖 Protocol Buffers 编译工具链) 较低(无需额外依赖,JSON 生态成熟)
适用场景 高内聚微服务(例如:需要低延迟的内部通信) 轻量级服务、Web 应用、前端与后端通信(REST 风格)

3. 典型使用场景

gRPC 适用场景
  • 高性能需求:微服务内部通信、需要低延迟和高吞吐量的场景。
  • 语言异构性:跨语言服务调用(如 Java 后端调用 Go 的服务)。
  • 流式数据处理:实时数据传输(如 IoT 设备数据推送、实时日志监控)。
  • 需要强类型安全:通过 Protocol Buffers 的 .proto 文件定义接口,确保接口强一致性。
JSON-RPC 适用场景
  • 简单服务间通信:轻量级服务间交互,无需复杂性能优化。
  • Web 前端集成:前端通过 HTTP 与后端直接通信(如通过浏览器调用后端 API)。
  • 快速原型开发:无需编译步骤,直接通过 JSON 构造请求,适合敏捷开发场景。
  • 遗留系统兼容性:老旧系统中已有 JSON 处理能力,无需引入新的协议栈。

4. 优缺点总结

gRPC 的优点
  • 性能高效:二进制格式减少网络开销,HTTP/2 的多路复用提升连接效率。
  • 强类型支持:通过 .proto 文件定义接口,代码生成工具自动处理序列化/反序列化。
  • 双向流:支持实时性强的双向通信场景。
  • 安全集成:内置对 TLS 和 JWT 的支持,且有成熟的插件生态(如 gRPC-gateway 可生成 REST API)。
gRPC 的缺点
  • 复杂度较高:依赖 Protocol Buffers 的编译工具链,学习曲线较陡。
  • 客户端浏览器支持有限:大多数浏览器未直接支持 HTTP/2 的流式交互,需通过代理或 gRPC-Web 方案。
  • 调试较麻烦:二进制格式不利于直接查看流量内容。
JSON-RPC 的优点
  • 轻量易用:无依赖,基于通用的 HTTP/JSON,开发简单。
  • 可读性强:JSON 格式便于调试和人眼阅读。
  • 浏览器友好:天然支持标准 HTTP/1.1,可直接通过 JavaScript 调用。
JSON-RPC 的缺点
  • 性能较低:JSON 的文本格式导致序列化/反序列化开销大,且 HTTP/1.1 头部冗余。
  • 无接口强约束:易出现接口一致性问题,依赖文档维护。
  • 无流式支持:单向请求-响应模型,不适合实时交互。

5. 如何选择?

  • 选 gRPC

    • 内部微服务通信需高性能、低延迟。
    • 跨语言且需要强类型接口定义。
    • 需要流式实时通信(如实时数据推送)。
    • 接口稳定性要求高(通过编译时检查避免类型不一致)。
  • 选 JSON-RPC

    • 场景简单且对性能要求不苛刻。
    • 需要与 Web 前端直接交互(如通过浏览器向后端发起请求)。
    • 快速实现或 MVP(最小可行产品)阶段。
    • 服务间协议必须保持高度灵活性(如需动态扩展字段)。

6. 补充说明

  • JSON-over-gRPC:可通过 google.protobuf.StructJSONPB 在 gRPC 消息中嵌入 JSON 数据,兼顾二进制效率和灵活性。
  • gRPC-Web:通过代理(如 Envoy 或自建网关)将 gRPC 的 HTTP/2 协议转换为 HTTP/1.1,适用于浏览器支持。
  • JSON-RPC 3:标准化的 JSON-RPC 3.0 提供了更灵活的扩展机制,但实际应用中仍以 2.0 协议为主。


网站公告

今日签到

点亮在社区的每一天
去签到