JSON-RPC 2.0 规范解读

🕒 2025-11-15 📁 前后端 👤 laumy 🔥 16 热度

概述

JSON-RPC是一种无状态、轻量的远程调用(RPC)协议,其有一套规范,定义了若干数据结构及其处理规则。它对传输层是无关的,可以在同一进程中传递使用,也可以跨进程、跨环境如socket、http等传递环境使用。

官方对JSON-RPC 2.0的规范定义其实也非常简单,主要请求对象、响应对象。

请求对象

一个RPC调用是通过向服务器发送一个Request对象来表示。

{
  "jsonrpc": "2.0",
  "method": "xxx",
  "params": ...,
  "id": ...
}

Rrequest对象具体有以下成员:

  • jsonrpc:一个指定JSON-RPC协议版本的字符串,必须正好是”2.0″。该成员必须。
  • method:一个包含要调用的方法名称字符串,用于区分要调用的是那个方法。该成员必须。
  • params:一个结构化智,用于存储方法调用期间要使用的参数值。该成员可省略。
  • id:由客户端建立的标识符,如果包含必须是一个字符串、数字或NULL值。

可以理解为method就是函数名,params就是函数的参数。

params是可以省略的,id的如果请求需要回复是不必须要的,如果请求不需要回复就不需要带,这种一般是通知。

通知

request对象可以分为带回复的请求,和不需要回复的请求,后者成为notification,跟BLE的传输协议是不是有点像?(没错就是notify和indicate的区别)。

(1)请求需要回复的示例

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "get_temp",
  "params": {}
}

(2)通知(请求不需要回复)

{
  "jsonrpc": "2.0",
  "method": "robot.chassis.forward",
  "params": { "speed": 0.5 }
}

通知是一个不需要id成员的请求对象,一个作为通知的请求对象表示客户端对相应的响应对象都不感兴趣,因此不需要向客户端返回响应对象。服务器必须不回复通知,包括哪些在批量请求中的通知。

根据定义,通知是不可确认的,因为它们没有要返回的响应对象。因此,客户端不会知道任何错误(例如无效的参数、内部错误)。

参数结构

参数是可选的,如果存在参数,rpc调用的参数必须以结构化值的形式提供。可以通过array数组按位置提供或通过object对象按名称提供。

  • 按数组位置提供: params必须是一个数组,其中包含服务器期望的顺序值。
  • 按对象名称提供:params必须是一个对象,其成员名称必须与服务器期望的参数名称匹配。缺少预期名称可能会导致生成错误。名称必须完全匹配,包括大小写,以匹配方法期望的参数。

(1)按数组位置

"params": [value1, value2, value3]

参数顺序必须完全匹配,客户端与服务器双方必须清楚位置含义,如果顺序错了就调用失败(服务器无法解析),参数数目要匹配缺少或多给都会报错。如下:

{
  "jsonrpc": "2.0",
  "method": "add",
  "params": [3, 5],
  "id": 1
}

这种一般适用于资源小,带宽紧张的事实控制,参数稍而且固定的场景。

(2)按对象名称

"params": { "x": 1, "y": 2, "speed": 0.5 }

按对象名称提供的最灵活,最容易读,这是一个键-值对的方式,但是参数的名称必须要完全匹配(包括大小写),参数的顺序没有要求。如下示例:

{
  "jsonrpc": "2.0",
  "method": "robot.arm.move",
  "params": {
    "joint1": 10,
    "joint2": -5
  },
  "id": 1
}

按数组的方式可以理解为只有原始数据,没有对应数据的标签。而按照对象的方式有数据和对应的标签。

响应对象

当发起一个rpc调用时,除了通知外,服务器都需要进行响应回复。响应分为正常的响应和错误的响应。

成功的响应,格式如下:

{
  "jsonrpc": "2.0",
  "result": ...,
  "id": ...
}

错误的响应:

{
  "jsonrpc": "2.0",
  "error": {
    "code": ...,
    "message": ....
  },
  "id": ...
}

响应表示为一个JSON对象,包含一下成员:

  • jsonrpc:一个指定JSON-RPC协议版本的字符串,必须正好是2.0。
  • result:成功的响应必须包含。
  • error:错误的响应必须包含。
  • id: 该成员必须,必须与请求对象的id成员值相同,表示一一对应。

成功响应

成功响应回复的是result的成员,示例如下:

{
  "id": 2,
  "jsonrpc": "2.0",
  "result": {
    "temperature": 3,
    "desc": "Sunny"
  }
}

错误响应

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "speed must be 0~1"
  }
}

错误的响应官方提供了标准的错误码含义。

code 含义
-32700 Parse error 解析错误
-32600 Invalid Request 无效请求
-32601 Method not found 找不到方法
-32602 Invalid params 参数错误
-32603 Internal error 内部错误
-32000 to -32099 保留用于实现定义的服务器错误。

批量调用

同时发送多个 Request 对象时,客户端可以发送一个包含 Request 对象的数组。服务器在处理完所有批量的request对象后,应返回一个包含相应response对象的数组。每个request对象都应该有一个对象的response对象,但通知不应有任何response对象。服务器可以将批量rpc调用作为一组并发处理,以任意顺序和任意并行度进行处理。

从批量调用返回的response对象可以在数组中按任意顺序返回。客户端应根据每个对象的id成员,在request对象集和结果response对象集之间匹配上下文。

如果批量rpc调用本身无法被识别为有效的JSON或至少包含一个值的数组,服务器的响应必须是一个单独的response对象。如果发送给客户端response数组中不包含任何response对象,服务器不得返回空数组,而应什么也不返回。

以下是示例一次发多个请求:

[
  { "jsonrpc": "2.0", "id": 1, "method": "get_temp" },
  { "jsonrpc": "2.0", "id": 2, "method": "get_humidity" }
]

响应:

[
  { "jsonrpc": "2.0", "id": 1, "result": 25 },
  { "jsonrpc": "2.0", "id": 2, "result": 60 }
]

这种批量的调用一般在多传感器融合的时候非常好用。

发表你的看法

\t