JSON-RPC 2.0 详解
JSON-RPC 2.0 是一种轻量级、无状态的远程过程调用(RPC)协议,基于 JSON 格式传输数据,适用于客户端-服务器架构(可跨语言、跨平台)。其核心目标是简化远程调用流程,同时保持灵活性和通用性,广泛用于 API 交互、微服务通信等场景。
一、核心特性
- 无状态:每次请求独立,服务器不存储客户端状态;
- 语言无关:仅定义数据格式(JSON),不限定实现语言(Java、Python、Go、JS 等均支持);
- 简洁性:协议规范极简,仅定义必要的请求/响应字段;
- 支持同步/异步 :可通过
id字段控制(有id为同步请求,无id为通知/异步); - 错误标准化:定义统一的错误码格式,便于问题定位。
二、核心概念
1. 数据交换格式
所有通信数据均为 JSON 对象,编码采用 UTF-8(强制要求)。
- 传输方式:支持 HTTP、TCP、WebSocket 等(HTTP 最常用,通常用 POST 方法);
- Content-Type:HTTP 传输时需指定为
application/json-rpc(建议,部分实现兼容application/json)。
2. 关键字段说明
| 字段名 | 类型 | 必选/可选 | 作用描述 |
|---|---|---|---|
jsonrpc |
字符串 | 必选 | 协议版本,必须为 "2.0"(区分 1.0 版本) |
method |
字符串 | 请求必选 | 要调用的远程方法名(需符合标识符规则,不能以 rpc. 开头,为系统保留) |
params |
数组/对象 | 可选 | 方法参数(数组:按顺序传参;对象:按名称传参,推荐用对象提升可读性) |
id |
整数/字符串/Null | 可选 | 请求唯一标识(用于匹配响应): - 有 id:客户端期望响应(同步请求); - 无 id:通知(异步,服务器不返回响应); - 不能用 Null 以外的无效 JSON 类型 |
result |
任意类型 | 成功响应必选 | 方法调用成功的返回结果(无结果时可为 Null) |
error |
对象 | 失败响应必选 | 方法调用失败的错误信息(格式见下文"错误处理") |
三、请求类型与示例
JSON-RPC 2.0 有 3 种请求类型:单请求、批量请求、通知。
1. 单请求(带 id,期望响应)
(1)参数为对象(推荐)
json
// 客户端请求(调用 getUser 方法,传入 id=123)
{
"jsonrpc": "2.0",
"method": "getUser",
"params": { "id": 123 },
"id": "req-001" // 字符串类型 id,也可设为整数(如 1)
}
(2)参数为数组(按顺序传参)
json
// 客户端请求(调用 add 方法,传入 10 和 20,顺序对应方法参数列表)
{
"jsonrpc": "2.0",
"method": "add",
"params": [10, 20],
"id": 1
}
2. 通知(无 id,无需响应)
客户端发送后不期望服务器返回结果(异步调用):
json
// 客户端通知(调用 log 方法,记录操作日志)
{
"jsonrpc": "2.0",
"method": "log",
"params": { "action": "login", "user": "admin" }
// 无 id 字段
}
3. 批量请求(数组格式,支持混合请求/通知)
客户端一次性发送多个请求,服务器按顺序返回响应(通知无响应):
json
// 客户端批量请求
[
// 第一个:带 id 的请求
{ "jsonrpc": "2.0", "method": "add", "params": [1,2], "id": 2 },
// 第二个:通知(无响应)
{ "jsonrpc": "2.0", "method": "log", "params": { "msg": "batch call" } },
// 第三个:带 id 的请求
{ "jsonrpc": "2.0", "method": "getUser", "params": { "id": 456 }, "id": 3 }
]
四、响应类型与示例
响应必须与请求的 id 一一对应(通知无响应),分为 成功响应 和 失败响应。
1. 成功响应(含 result)
json
// 对应上文 add 方法的成功响应(id 与请求一致)
{
"jsonrpc": "2.0",
"result": 30, // add(10,20) 的结果
"id": 1
}
2. 失败响应(含 error)
error 对象必须包含 3 个字段:code(错误码)、message(错误描述)、data(可选附加信息)。
标准错误码(协议定义,不可自定义)
| 错误码 | 含义描述 |
|---|---|
| -32700 | 解析错误:请求 JSON 格式无效 |
| -32600 | 无效请求:JSON 格式有效,但不符合 RPC 规范(如缺少 jsonrpc: "2.0") |
| -32601 | 方法未找到:请求的 method 不存在 |
| -32602 | 参数错误:params 格式错误或参数不匹配 |
| -32603 | 内部错误:服务器执行方法时发生未知错误 |
| -32000~-32099 | 服务器自定义错误:需在文档中说明具体含义 |
失败响应示例
json
// 对应上文 getUser 方法的失败响应(用户不存在)
{
"jsonrpc": "2.0",
"error": {
"code": -32602, // 参数错误(或自定义码 -32001 表示"用户不存在")
"message": "User not found",
"data": { "userId": 123 } // 附加信息(可选)
},
"id": "req-001" // 与请求 id 一致
}
3. 批量响应
对应批量请求,返回数组格式的响应(通知无响应,不包含在结果中):
json
// 对应上文批量请求的响应(仅返回带 id 的请求结果)
[
{ "jsonrpc": "2.0", "result": 3, "id": 2 }, // add(1,2) 的结果
{ "jsonrpc": "2.0", "result": { "id": 456, "name": "user2" }, "id": 3 } // getUser 的结果
]
五、关键约束与注意事项
- 版本强制 :
jsonrpc字段必须为字符串"2.0",大小写敏感; - id 匹配规则 :
- 请求的
id若为非 Null 有效值,响应必须返回相同id; - 若请求
id无效(如True、空对象),服务器返回id: Null的错误响应;
- 请求的
- 参数格式 :
params只能是数组或对象,不能是字符串、数字等原始类型; - 方法名约束 :
method不能以rpc.开头(系统保留前缀); - HTTP 传输建议 :
- 仅支持 POST 方法(GET 方法不适合携带复杂
params); - 响应状态码:成功用 200 OK,解析错误用 400 Bad Request,服务器错误用 500 Internal Server Error;
- 仅支持 POST 方法(GET 方法不适合携带复杂
- 批量请求限制 :若批量请求为空数组(
[]),服务器返回-32600无效请求错误。
六、跨语言实现示例
1. Python 服务端(使用 jsonrpcserver 库)
bash
pip install jsonrpcserver
python
from jsonrpcserver import method, serve
# 定义远程方法
@method
def add(a: int, b: int) -> int:
return a + b
@method
def getUser(id: int) -> dict:
if id == 123:
return {"id": 123, "name": "Alice"}
raise Exception("User not found") # 抛出异常会转为错误响应
# 启动服务(默认端口 5000)
if __name__ == "__main__":
serve()
2. Python 客户端(使用 jsonrpcclient 库)
bash
pip install jsonrpcclient
python
from jsonrpcclient import request, parse_response
# 发送请求
response = request("http://localhost:5000", "add", a=10, b=20)
result = parse_response(response)
print(result) # 输出:30
# 发送带参数的 getUser 请求
response = request("http://localhost:5000", "getUser", id=123)
result = parse_response(response)
print(result) # 输出:{'id': 123, 'name': 'Alice'}
3. JavaScript 客户端(浏览器/Node.js)
javascript
// 浏览器端示例(使用 fetch)
async function callRpc(method, params) {
const response = await fetch("http://localhost:5000", {
method: "POST",
headers: { "Content-Type": "application/json-rpc" },
body: JSON.stringify({
jsonrpc: "2.0",
method,
params,
id: Date.now().toString() // 用时间戳作为唯一 id
})
});
const data = await response.json();
if (data.error) throw new Error(`${data.error.code}: ${data.error.message}`);
return data.result;
}
// 调用 add 方法
callRpc("add", { a: 10, b: 20 }).then(console.log); // 输出 30
七、适用场景与对比
适用场景
- 轻量级 API 交互(如前后端通信、微服务间调用);
- 跨语言/跨平台通信(JSON 通用性强);
- 对协议复杂度敏感的场景(相比 gRPC 更简单,无需 proto 定义)。
与其他 RPC 协议对比
| 协议 | 优点 | 缺点 |
|---|---|---|
| JSON-RPC 2.0 | 简单、无依赖、跨语言友好、易调试 | 无类型校验、不支持流式传输、性能一般 |
| gRPC | 强类型、高性能、支持流式/双向通信 | 依赖 proto 文件、学习成本高、调试复杂 |
| XML-RPC | 成熟、跨语言支持广 | XML 冗余、解析效率低 |
总结
JSON-RPC 2.0 是"极简实用"的 RPC 协议,核心价值在于简单性和通用性 。无需复杂的配置或定义,仅通过 JSON 格式的请求/响应即可实现远程调用,适合对性能要求不极致、追求开发效率的场景。使用时需严格遵守字段规范(尤其是 jsonrpc: "2.0" 和 id 匹配),同时合理利用错误码和批量请求提升开发效率。
官方规范文档:JSON-RPC 2.0 Specification