深入解析 JSON-RPC:从基础到高级应用(附调用示例)

news2025/3/31 0:16:54

在当今的软件开发领域,远程过程调用(RPC)技术是实现分布式系统间通信的关键手段之一。JSON-RPC,作为一种基于 JSON 数据格式的轻量级 RPC 协议,因其简洁性和高效性而备受青睐。本文将全面深入地探讨 JSON-RPC 的核心概念、请求与响应机制、错误处理、批处理特性,以及如何在实际开发中高效地应用 JSON-RPC,帮助读者从基础到高级层面全面掌握这一技术。

JSON-RPC 简介

JSON-RPC 是一种无状态、轻量级的远程过程调用(RPC)协议,主要用于在不同系统或服务之间进行通信。它基于 JSON(JavaScript Object Notation)数据格式,使得数据交换变得简单且高效。JSON-RPC 的设计目标是简单易用,同时保持足够的灵活性以满足各种应用场景的需求。它支持多种传输方式,包括 HTTP、WebSocket 等,这使得 JSON-RPC 可以在不同的网络环境中使用。

JSON-RPC 请求对象

在 JSON-RPC 中,请求对象是客户端向服务器发送的 JSON 格式的数据,用于请求服务器执行某个方法。请求对象包含以下字段:

  • jsonrpc:一个字符串,指定 JSON-RPC 协议的版本。对于 JSON-RPC 2.0,该字段的值必须是 "2.0"
  • method:一个字符串,表示要调用的方法名称。
  • params:一个可选的字段,可以是 JSON 数组或对象,用于传递方法调用所需的参数。
  • id:一个可选的字段,用于标识请求。如果存在,它必须是一个字符串、数字或 null。如果不存在,该请求被视为通知(notification),服务器不需要返回响应。

示例请求对象

{
  "jsonrpc": "2.0",
  "method": "subtract",
  "params": [42, 23],
  "id": 1
}

请求对象的构造

在构造请求对象时,需要注意以下几点:

  • jsonrpc 字段:必须始终设置为 "2.0",以确保使用的是 JSON-RPC 2.0 协议。
  • method 字段:方法名称必须是一个字符串,且服务器必须支持该方法。
  • params 字段:如果存在,必须是 JSON 数组或对象。如果是数组,参数按位置传递;如果是对象,参数按名称传递。
  • id 字段:如果存在,必须是唯一的(对于批处理请求)。如果不存在,请求被视为通知,服务器不会返回响应。

JSON-RPC 响应对象

当服务器接收到一个有效的请求对象时,它会返回一个响应对象。响应对象包含以下字段:

  • jsonrpc:一个字符串,指定 JSON-RPC 协议的版本。对于 JSON-RPC 2.0,该字段的值必须是 "2.0"
  • result:一个可选的字段,表示方法调用的结果。如果请求成功,该字段必须存在,且包含方法的返回值。
  • error:一个可选的字段,表示方法调用过程中发生的错误。如果请求失败,该字段必须存在,且包含错误信息。
  • id:一个字段,与请求对象中的 id 字段相对应,用于标识响应。

示例响应对象

{
  "jsonrpc": "2.0",
  "result": 19,
  "id": 1
}

响应对象的构造

在构造响应对象时,需要注意以下几点:

  • jsonrpc 字段:必须始终设置为 "2.0",以确保使用的是 JSON-RPC 2.0 协议。
  • result 字段:如果请求成功,必须包含该字段,且值为方法的返回值。
  • error 字段:如果请求失败,必须包含该字段,且值为错误信息。
  • id 字段:必须与请求对象中的 id 字段一致,以便客户端能够匹配请求和响应。

JSON-RPC 错误对象

如果在方法调用过程中发生错误,服务器会返回一个包含错误信息的响应对象。错误对象包含以下字段:

  • code:一个数字,表示错误的类型。
  • message:一个字符串,提供错误的简短描述。
  • data:一个可选的字段,可以包含有关错误的额外信息。

示例错误对象

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "Method not found"
  },
  "id": 1
}

错误代码

JSON-RPC 2.0 定义了一系列标准错误代码,用于描述常见的错误情况:

代码消息含义
-32700Parse error服务器接收到无效的 JSON。在服务器解析 JSON 文本时发生错误。
-32600Invalid Request发送的 JSON 不是一个有效的请求对象。
-32601Method not found方法不存在 / 不可用。
-32602Invalid params方法参数无效。
-32603Internal error内部 JSON-RPC 错误。
-32000 至 -32099Server error保留用于实现定义的服务器错误。

JSON-RPC 批处理

JSON-RPC 支持批处理请求,允许客户端一次性发送多个请求对象。服务器会返回一个包含多个响应对象的数组。每个响应对象与一个请求对象相对应,但响应对象的顺序可能与请求对象的顺序不同。

示例批处理请求

[
  {
    "jsonrpc": "2.0",
    "method": "sum",
    "params": [1, 2, 4],
    "id": "1"
  },
  {
    "jsonrpc": "2.0",
    "method": "notify_hello",
    "params": [7]
  },
  {
    "jsonrpc": "2.0",
    "method": "subtract",
    "params": [42, 23],
    "id": "2"
  }
]

示例批处理响应

[
  {
    "jsonrpc": "2.0",
    "result": 7,
    "id": "1"
  },
  {
    "jsonrpc": "2.0",
    "result": 19,
    "id": "2"
  }
]

批处理请求的注意事项

  • 请求对象的顺序:批处理请求中的请求对象顺序可能与响应对象的顺序不同。
  • 通知:通知请求(没有 id 字段)不会返回响应对象。
  • 错误处理:如果批处理请求中的某个请求失败,服务器会返回一个包含错误信息的响应对象。

JSON-RPC 实践

在实际开发中,使用 JSON-RPC 时需要注意以下几点:

请求对象的构造

  • 确保请求对象符合规范:特别是 jsonrpc 字段必须是 "2.0"id 字段必须是唯一的(对于批处理请求)。
  • 使用辅助函数:例如 Params(),可以简化参数的构造过程。

错误处理

  • 处理服务器返回的错误:服务器返回的错误对象包含错误代码和描述,客户端应该根据这些信息进行适当的错误处理。
  • 处理网络错误:除了 JSON-RPC 错误,还需要处理网络错误和 HTTP 错误。

批处理请求

  • 提高效率:批处理请求可以减少网络往返次数,提高通信效率。
  • 注意响应顺序:响应对象的顺序可能与请求对象的顺序不同,客户端需要根据 id 字段匹配请求和响应。

安全性

  • 数据加密:在传输敏感数据时,应使用 HTTPS 或其他加密协议。
  • 身份验证:确保只有授权的客户端可以调用服务器上的方法。

示例代码

客户端示例

以下是一个使用 Python 和 requests 库发送 JSON-RPC 请求的示例:

import requests
import json

# 定义请求对象
request = {
    "jsonrpc": "2.0",
    "method": "subtract",
    "params": [42, 23],
    "id": 1
}

# 发送请求
response = requests.post("http://127.0.0.1:5000/jsonrpc", json=request)

# 解析响应
response_data = response.json()

# 打印结果
print(response_data)

服务器示例

以下是一个使用 Python 和 Flask 框架实现的简单 JSON-RPC 服务器示例:

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/jsonrpc', methods=['POST'])
def jsonrpc():
    data = request.json
    if isinstance(data, list):
        responses = []
        for req in data:
            if req['jsonrpc'] != '2.0':
                responses.append({
                    "jsonrpc": "2.0",
                    "error": {
                        "code": -32600,
                        "message": "Invalid Request"
                    },
                    "id": None
                })
                continue

            method = req.get('method')
            params = req.get('params', [])
            id_ = req.get('id')

            if method == 'sum':
                if not isinstance(params, list) or len(params) < 1:
                    responses.append({
                        "jsonrpc": "2.0",
                        "error": {
                            "code": -32602,
                            "message": "Invalid params"
                        },
                        "id": id_
                    })
                    continue
                result = sum(params)
                responses.append({
                    "jsonrpc": "2.0",
                    "result": result,
                    "id": id_
                })
            elif method == 'subtract':
                if not isinstance(params, list) or len(params) != 2:
                    responses.append({
                        "jsonrpc": "2.0",
                        "error": {
                            "code": -32602,
                            "message": "Invalid params"
                        },
                        "id": id_
                    })
                    continue
                result = params[0] - params[1]
                responses.append({
                    "jsonrpc": "2.0",
                    "result": result,
                    "id": id_
                })
            else:
                responses.append({
                    "jsonrpc": "2.0",
                    "error": {
                        "code": -32601,
                        "message": "Method not found"
                    },
                    "id": id_
                })
        return jsonify(responses)
    else:
        if data['jsonrpc'] != '2.0':
            return jsonify({
                "jsonrpc": "2.0",
                "error": {
                    "code": -32600,
                    "message": "Invalid Request"
                },
                "id": None
            }), 400

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

        if method == 'sum':
            if not isinstance(params, list) or len(params) < 1:
                return jsonify({
                    "jsonrpc": "2.0",
                    "error": {
                        "code": -32602,
                        "message": "Invalid params"
                    },
                    "id": id_
                }), 400
            result = sum(params)
            return jsonify({
                "jsonrpc": "2.0",
                "result": result,
                "id": id_
            })
        elif method == 'subtract':
            if not isinstance(params, list) or len(params) != 2:
                return jsonify({
                    "jsonrpc": "2.0",
                    "error": {
                        "code": -32602,
                        "message": "Invalid params"
                    },
                    "id": id_
                }), 400
            result = params[0] - params[1]
            return jsonify({
                "jsonrpc": "2.0",
                "result": result,
                "id": id_
            })
        else:
            return jsonify({
                "jsonrpc": "2.0",
                "error": {
                    "code": -32601,
                    "message": "Method not found"
                },
                "id": id_
            }), 404

if __name__ == '__main__':
    app.run(debug=True)

客户端和服务端交互示例

  1. 启动服务器

    python server.py
    
  2. 发送单个请求

    import requests
    import json
    
    # 定义请求对象
    request = {
        "jsonrpc": "2.0",
        "method": "subtract",
        "params": [42, 23],
        "id": 1
    }
    
    # 发送请求
    response = requests.post("http://127.0.0.1:5000/jsonrpc", json=request)
    
    # 解析响应
    response_data = response.json()
    
    # 打印结果
    print(response_data)
    

    输出

    {
      "jsonrpc": "2.0",
      "result": 19,
      "id": 1
    }
    
  3. 发送批处理请求

    import requests
    import json
    
    # 定义批处理请求对象
    requests_batch = [
        {
            "jsonrpc": "2.0",
            "method": "sum",
            "params": [1, 2, 4],
            "id": "1"
        },
        {
            "jsonrpc": "2.0",
            "method": "subtract",
            "params": [42, 23],
            "id": "2"
        }
    ]
    
    # 发送批处理请求
    response = requests.post("http://127.0.0.1:5000/jsonrpc", json=requests_batch)
    
    # 解析响应
    response_data = response.json()
    
    # 打印结果
    print(response_data)
    

    输出

    [
      {
        "jsonrpc": "2.0",
        "result": 7,
        "id": "1"
      },
      {
        "jsonrpc": "2.0",
        "result": 19,
        "id": "2"
      }
    ]
    

结论

通过本文的详细介绍和示例代码,你应该对 JSON-RPC 有了更深入的理解。JSON-RPC 是一种简单而强大的远程过程调用协议,适用于各种应用场景。通过理解其基本概念和结构,开发者可以更高效地使用 JSON-RPC 进行系统间通信。希望本文能帮助你在实际开发中实现高效、可靠的分布式系统通信。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2323781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用 Postman 正确传递 Date 类型参数,避免服务器解析错误?

如何在 Postman 中传递 Date 类型参数。调试工具如何模拟发送用户端的当前时间呢&#xff1f; Postman 传递 Date 类型参数教程

JUC 03

今天是2025/03/28 20:46 day 14 总路线请移步主页Java大纲相关文章 今天进行JUC 6,7,8 个模块的归纳 首先是JUC的相关内容概括的思维导图 由于内容比较多且重要&#xff0c; 个人还整理了一份详细JUC的思维导图&#xff0c;需要的请评论。是 xmind文件 6. 锁机制 深入解析…

CentOS 7 部署RuoYi 项目

换源 备份现有的 YUM 源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 默认的 CentOS 官方镜像源替换为阿里云的镜像源&#xff0c;以提高下载速度和稳定性。 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.co…

【JavaScript】八、对象

文章目录 1、对象的声明2、对象的使用3、对象中的方法4、遍历对象5、内置对象Math 1、对象的声明 一种数据类型&#xff0c;使用typeof查看类型&#xff0c;结果是object可以详细的描述描述某个事物 声明语法&#xff1a; // 多用花括号形式声明 // 比如声明一个person对象 …

Processor System Reset IP 核 v5.0(vivado)

这个IP的作用&#xff0c;我的理解是&#xff0c;比普通按键复位更加高效灵活&#xff0c;可以配置多个复位输出&#xff0c;可以配置复位周期。 1、输入信号&#xff1a; 重要的信号有时钟clk信号&#xff0c;一般连接到系统时钟&#xff1b;输入复位信号&#xff0c;一般是外…

linux0.11内核源码修仙传第十一章——硬盘初始化

&#x1f680; 前言 本文是初始化最后一部分了&#xff0c;对硬盘的初始化&#xff0c;对应于书中的第20回。希望各位给个三连&#xff0c;拜托啦&#xff0c;这对我真的很重要&#xff01;&#xff01;&#xff01; 目录 &#x1f680; 前言&#x1f3c6;块设备管理&#x1f3…

包络解调在故障诊断中的应用-广义检波解调案例

前言 前面我们曾介绍过广义检波解调的原理&#xff0c;那么今天就将学过的知识点真正用在故障诊断上&#xff0c;由于工厂数据集不能轻易获取&#xff0c;因此通过实验室仿真数据集来介绍整个诊断流程。 数据集 加拿大渥太华是故障诊断领域蛮出名的一个数据集&#xff0c;其…

喜报|迪捷软件入选工信部“2024年信息技术应用创新解决方案”

为进一步深化行业信息技术应用创新&#xff0c;健全信息技术应用创新产业生态&#xff0c;加快新技术新产品应用推广&#xff0c;强化应用牵引和需求导向&#xff0c;加强区域联动和资源整合&#xff0c;工业和信息化部网络安全产业发展中心&#xff08;工业和信息化部信息中心…

2.Python 计算机二级题库:选择题答案解析

一 对 题目1 题目2 题目3 补充&#xff1a;在 Python 中&#xff0c;数字类型的复数类型是 complex。 题目4 题目5 题目6 题目7 题目8 题目9 题目10 题目11 题目12 题目13 题目14 题目15 题目16 题目17 题目18 题目19 题目20 题目21 题目22 题目23 题目24 题目25 题目26 题目27…

使用Selenium和lxml库搜房网爬取某地区房屋信息(python、pycharm爬虫)

一、地址&#xff1a; url "https://zb.newhouse.fang.com/house/s/b91" # 第一页的 URL 但是这个爬虫我不知道为啥总是翻不了页数&#xff0c;请帮忙修改一下~ 二、用到的知识点以及代码详解&#xff1a; 这段代码是一个使用Selenium和lxml库实现的网页爬虫&a…

大模型训练过程中KVCache与MLA

基础内容 在Transformer模型中&#xff0c;每个token有qkv三个属性&#xff0c;分别通过神经网络变换得到。1 根据Transformer中注意力公式&#xff0c;每个token的q需要和之前所有的k计算注意力&#xff0c;然后经过Softmax函数后乘以之前所有token的V&#xff0c;得到最终的…

材质及制作笔记

基本流程&#xff1a; 建中模——zb雕刻高模——maya拓扑低模——拆uv——sp烘焙贴图——sp绘制材质——渲染 1 材质贴图&#xff1a; diffuse/albedo/basecolor&#xff1a;漫反射 reflection/specular&#xff1a;反射 metalness&#xff1a;金属度 glossiness&#xf…

语音机器人与智能体结合

自从春节期间deepseek的发布&#xff0c;大家对语音机器人接入大模型格外的关注。最近又收到一个需求&#xff0c;是语音机器人与智能体的结合。 什么是智能体&#xff1f; 智能体&#xff08;Agent&#xff09;是指能够感知环境并采取行动以实现目标的实体。根据其复杂程度&am…

Axios企业级封装实战:从拦截器到安全策略!!!

&#x1f680; Axios企业级封装实战&#xff1a;从拦截器到安全策略 &#x1f527; 核心代码解析 // 创建Axios实例 const service axios.create({baseURL: api, // &#x1f310; 全局API前缀timeout: 0, // ⏳ 永不超时&#xff08;慎用&#xff01;&#xff09;withCrede…

Zerotier虚拟局域网在树莓派的应用和Syncthing配合Zerotier实现端到端文件同步

一、Zerotier的部署 1、官网注册账号 https://my.zerotier.com/i 2、选择linux系统&#xff0c;执行安装Zerotier curl -s https://install.zerotier.com | sudo bash3、将树莓派网络加入Zerotier zerotier-cli join DB62228FEDF6CE55DB62228FEDF6CE55 为你的Zerotier IP 需…

51c嵌入式~三极管~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/12208603 一、PNP与NPN两种三极管使用方法 分享这篇文章总结下关于NPN和PNP两种型号三极管的使用和连接方法。 在单片机应用电路中三极管主要的作用就是开关作用。 PNP与NPN两种三极管使用方法 上图中&#xff0c;横向左…

SQL中累计求和与滑动求和函数sum() over()的用法

[TOC](SQL中累计求和与滑动求和函数sum() over()的用法) 一、窗口函数功能简介 sum(c) over(partition by a order by b) 按照一定规则汇总c的值&#xff0c;具体规则为以a分组&#xff0c;每组内按照b进行排序&#xff0c;汇总第一行至当前行的c的加和值。 sum()&#xff1a…

【Sql Server】在SQL Server中生成雪花ID(Snowflake ID)

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言认识雪花ID…

FPGA——分秒计数器设计(DE2-115开发板)

一、项目创建 1.创建工程 点击File->New Project Wizard...或者直接在页面处点击 在第一行选择文件存放地点&#xff0c;第二行为项目名称&#xff0c;第三行为顶级设计实体名称 &#xff08;下面的步骤可以暂时不做直接点Finish&#xff0c;因为是先写代码先把它跑出来暂…

雅思练习总结(九)

雅思练习总结&#xff08;九&#xff09; 本文章是雅思练习总结&#xff08;九&#xff09;&#xff0c;总结了文章《BAKELITE》&#xff0c;内容包括原文精翻&#xff0c;文章脉络总结&#xff0c;单词扩展学习3个部分 1 文章原文及翻译 BAKELITE 翻译&#xff1a;贝克莱特…