本文字数:4000 字,阅读约需 15 分钟。
分布式系统中,不同服务之间需要一种可靠的方式来通信。远程过程调用(RPC)是一种常见的选择,而 JSON-RPC 是其中比较简单的一种。
这篇文章介绍 JSON-RPC 2.0 协议的核心内容,包括消息格式、错误处理和实际应用场景。
JSON-RPC 是一种无状态、轻量级的远程过程调用协议,使用 JSON 作为数据格式。它的设计目标就是简单——协议规范只有几页文档。
JSON 作为数据交换格式,几乎所有主流编程语言都有良好的支持,包括 JavaScript、Python、Java、C#、Go 等。这使得 JSON-RPC 能够轻松实现跨语言调用。
协议本身不绑定传输层,可以跑在 HTTP、WebSocket、TCP Socket 等各种消息传输环境上。开发者可以根据业务需求选择合适的传输方式。
JSON-RPC 有两个主要版本:1.0 和 2.0。
1.0 版本最早提出了基于 JSON 的 RPC 概念,但在规范性方面有所欠缺。2010 年发布的 2.0 版本做了重要升级,加入了批量调用支持、统一的错误对象结构。两个版本通过 jsonrpc 字段来区分。
JSON-RPC 有几个值得注意的特点:
JSON-RPC 规范中使用了 RFC 2119 定义的关键字:MUST、MUST NOT、SHOULD、SHOULD NOT、MAY。这些术语描述了实现者必须、应该或可以遵循的行为规范。
客户端(Client):发起请求的实体,负责构造请求对象并处理响应。
服务端(Server):接收请求并返回响应的实体,处理请求并生成响应。
同一个实现可以同时扮演客户端和服务端。比如在对等网络中,两个节点可能既向对方发起请求,也响应来自对方的请求。
JSON-RPC 继承自 JSON 的类型系统,包含六种数据类型:
基本类型:String(字符串)、Number(数值)、Boolean(布尔值)、Null(空值)
结构化类型:Object(对象)、Array(数组)
这些类型名称首字母必须大写,包括 True 和 False。
成员名称(字段名)在客户端与服务端之间交换时必须区分大小写。函数、方法、过程这三个术语可以互换使用,都指向可以被调用的可执行单元。
JSON-RPC 2.0 定义了三种核心消息类型:请求对象(Request Object)、响应对象(Response Object) 和 通知对象(Notification Object)。

JSON-RPC 协议架构图
请求对象是客户端向服务端发起 RPC 调用的载体:
{
"jsonrpc": "2.0",
"method": "subtract",
"params": [42, 23],
"id": 1
}
rpc.subscribe、rpc.notify。// 索引数组参数:参数顺序与服务端预期一致
{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
// 命名对象参数:参数名需与服务端方法签名匹配
{"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 2}
响应对象是服务端返回给客户端的执行结果:
// 成功响应
{
"jsonrpc": "2.0",
"result": 19,
"id": 1
}
// 错误响应
{
"jsonrpc": "2.0",
"error": {
"code": -32601,
"message": "Method not found",
"data": "详细错误信息"
},
"id": 1
}
响应对象必须包含 result 或 error 之一,不能同时包含两者。id 必须与对应请求中的 id 保持一致。
如果请求本身存在错误(如无效的 JSON 格式或非法请求结构),导致服务端无法确定原始 id 时,响应中的 id 必须为 null。
通知是一种不需要响应的请求,通过省略 id 字段来标识:
{
"jsonrpc": "2.0",
"method": "update",
"params": [1, 2, 3, 4, 5]
}
通知适用于日志记录、事件发布、进度通知等场景。客户端只负责发送消息,不需要处理响应。
由于没有响应机制,客户端无法得知通知是否被成功处理。在批量请求中,通知请求不会产生对应的响应。

JSON-RPC 请求响应流程图
JSON-RPC 2.0 定义了标准化的错误对象:
{
"code": -32603,
"message": "Internal error",
"data": { "details": "数据库连接失败" }
}
JSON-RPC 2.0 在 -32768 到 -32000 范围内预留了预定义错误码:
错误码 | 名称 | 说明 |
|---|---|---|
-32700 | Parse Error | 解析错误,服务端收到的 JSON 格式无效 |
-32600 | Invalid Request | 无效请求,发送的不是有效的请求对象 |
-32601 | Method Not Found | 方法不存在或不可调用 |
-32602 | Invalid Params | 参数无效 |
-32603 | Internal Error | JSON-RPC 内部错误 |

JSON-RPC 错误码分类图
-32000 到 -32099 范围内的错误码保留给服务端自定义使用。应用程序也可以定义自己的错误码(通常为负数且绝对值小于 32767)。
JSON-RPC 2.0 支持在单个请求中发送多个 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", "method": "get_data", "id": "9"}
]
对应的批量响应:
[
{"jsonrpc": "2.0", "result": 7, "id": "1"},
{"jsonrpc": "2.0", "result": 19, "id": "2"},
{"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
]
通知请求(没有 id 字段)不会产生响应。响应数组中各元素的顺序与请求顺序无关,客户端通过匹配 id 来关联请求和响应。
规范对批量调用中的边界情况有明确定义:
如果批量请求本身不是有效的 JSON 或不是包含至少一个值的数组,服务端应返回单对象响应而非数组。空数组 [] 被视为无效请求。
如果批量请求中的所有请求都是通知,服务端不需要返回任何响应。其他情况下,即使某些请求处理失败,响应数组中仍应包含对应请求的错误响应。
JSON-RPC 和 RESTful 代表了两种不同的 API 设计哲学。JSON-RPC 是过程导向的,关注的是"做什么操作";RESTful 是资源导向的,关注的是"操作什么资源"。
以用户操作为例:
// JSON-RPC: 直接调用方法
{"jsonrpc": "2.0", "method": "createUser", "params": {"name": "张三", "email": "zhang@example.com"}, "id": 1}
// RESTful: 操作资源
POST /users
{"name": "张三", "email": "zhang@example.com"}
维度 | JSON-RPC | RESTful |
|---|---|---|
语义抽象 | 方法调用 | 资源操作 |
URL 角色 | 仅作为端点地址 | 表示资源路径 |
HTTP 方法 | 仅使用 POST | 充分利用 GET/POST/PUT/DELETE |
状态管理 | 可维护会话状态 | 倡导无状态设计 |
灵活性 | 更紧凑,适合精确控制 | 更灵活,适合通用场景 |

JSON-RPC 与 RESTful 对比图
适合使用 JSON-RPC 的场景:
适合使用 RESTful 的场景:
JSON-RPC 的简洁设计虽然降低了实现复杂度,但也带来了一些安全考量:

JSON-RPC 安全威胁与防护措施图
JSON-RPC 2.0 协议设计简洁,在分布式系统通信中有其适用场景。规范本身很短,学习和实现成本都不高,JSON 格式的请求/响应便于调试和日志记录。
当然,JSON-RPC 也有局限性。它缺少内置的元数据机制,类型系统相对简单。在需要高度标准化、复杂类型系统或强类型安全的场景中,可以考虑 gRPC、Thrift 等方案。
如果你的业务场景需要简单、透明的服务间通信方式,JSON-RPC 是一个值得考虑的选择。
都看到这里了,如果觉得有帮助,还请您给我个小小的鼓励,动动手指,帮忙点个在看或者点个赞👍🏻!谢谢喽!!!
关注我,持续分享后端开发经验!