JSON-RPC 2.0 规范
1. 概述
JSON-RPC 是一种无状态、轻量级的远程过程调用(RPC)协议。本规范主要定义了几种数据结构以及它们的处理规则。它与传输协议无关,能够在同一进程内、通过套接字、HTTP 或多种消息传递环境中使用。它使用 JSON(RFC 4627)作为数据格式。
设计上,它的目标是简洁明了。
2. 术语
文中使用的关键词如 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY” 和 “OPTIONAL” 的解释遵循 RFC 2119。
JSON-RPC 使用 JSON 作为数据格式,JSON 的类型系统包括四种原始类型(字符串、数字、布尔值和 null)以及两种结构化类型(对象和数组)。此文中提到的 JSON 类型首字母总是大写。
所有 Client 和 Server 之间交换的成员名称,特别是涉及匹配的,应该区分大小写。方法(method)和函数(function)、过程(procedure)可以视为同义词。
- Client:请求对象的发起者和响应对象的处理者。
- Server:响应对象的发起者和请求对象的处理者。
一个实现可以同时担任这两个角色,分别处理不同客户端或同一客户端的请求。
3. 兼容性
JSON-RPC 2.0 的请求对象和响应对象与现有的 JSON-RPC 1.0 客户端或服务器不兼容。2.0 版本始终包含名为 “jsonrpc” 的字段,值为 “2.0”;而 1.0 版本没有这个字段。大多数 2.0 实现应该尝试处理 1.0 对象,尽管不支持点对点或类提示的特性。
4. 请求对象
RPC 调用通过发送一个请求对象给服务器表示。请求对象包含以下成员:
- jsonrpc:指定 JSON-RPC 协议的版本。值必须为 “2.0”。
- method:包含要调用的方法名称。方法名称以 “rpc” 开头的为系统保留,不能使用。
- params:一个结构化的值,包含在方法调用时使用的参数。该字段可以省略。
- id:由客户端指定的标识符,必须是字符串、数字或 null。如果省略该字段,则默认为通知类型。若包含,服务器返回的响应对象也必须包含该值,以便关联上下文。
4.1 通知
通知是没有 “id” 字段的请求对象。通知意味着客户端不关心响应,因此服务器不需要返回响应。通知不能确认,因此客户端无法得知是否发生错误。
4.2 参数结构
参数可以通过位置或名称传递:
- 按位置传递:参数必须是一个数组,按照服务器预期的顺序传递。
- 按名称传递:参数必须是一个对象,其中成员名称应与服务器预期的参数名称完全匹配。
5. 响应对象
服务器在处理请求时会返回一个响应对象,除非是通知类型。响应对象包含以下成员:
- jsonrpc:指定 JSON-RPC 协议的版本。值必须为 “2.0”。
- result:在成功时返回,表示方法的返回值。出错时,该字段不能存在。
- error:在错误时返回,表示方法执行中的错误。没有错误时,该字段不能存在。包含错误详情的对象。
- id:与请求对象中的 id 值相同。如果请求对象的 id 无法识别,返回 null。
5.1 错误对象
当 RPC 调用遇到错误时,响应对象中的 error 字段会包含以下信息:
- code:一个整数,表示错误类型。
- message:简短的错误描述。
- data:一个可选的字段,包含错误的详细信息,值由服务器定义。
保留错误代码范围为 -32768 到 -32000,具体的错误代码定义如下:
错误代码 | 错误信息 | 含义 |
---|---|---|
-32700 | 解析错误 | 无效的 JSON 格式。服务器解析 JSON 时出错。 |
-32600 | 无效的请求 | 发送的 JSON 不是有效的请求对象。 |
-32601 | 方法未找到 | 方法不存在或不可用。 |
-32602 | 参数无效 | 方法参数无效。 |
-32603 | 内部错误 | 服务器内部错误。 |
-32000 到 -32099 | 服务器错误 | 预留的服务器实现错误。 |
6. 批量请求
客户端可以同时发送多个请求对象,服务器将处理并返回相应的响应对象。批量请求的响应是一个数组,包含每个请求的响应对象。
- 响应中的每个对象对应一个请求对象,通知类型的请求不会返回响应对象。
- 批量请求可以并行处理,服务器处理顺序和并行度可以自由选择。
- 如果批量请求本身无效,服务器返回一个单一的响应对象,而不是空数组。
7 示例
-
带位置参数的 RPC 调用:
--> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1} <-- {"jsonrpc": "2.0", "result": 19, "id": 1}--> {"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2} <-- {"jsonrpc": "2.0", "result": -19, "id": 2}
-
带命名参数的 RPC 调用:
--> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3} <-- {"jsonrpc": "2.0", "result": 19, "id": 3}--> {"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4} <-- {"jsonrpc": "2.0", "result": 19, "id": 4}
-
通知:
--> {"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]} --> {"jsonrpc": "2.0", "method": "foobar"}
-
调用不存在的方法:
--> {"jsonrpc": "2.0", "method": "foobar", "id": "1"} <-- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}
-
无效的 JSON 调用:
--> {"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz] <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
-
无效请求对象的调用:
--> {"jsonrpc": "2.0", "method": 1, "params": "bar"} <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
-
批量请求,含无效的 JSON:
--> [{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},{"jsonrpc": "2.0", "method": "foobar"} ] <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
-
带空数组的请求:
--> [] <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
-
带无效元素的批量请求:
--> [1] <-- [{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null} ]
-
无效的批量请求:
--> [1,2,3] <-- [{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null} ]
-
批量请求:
--> [{"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"},{"foo": "boo"},{"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},{"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", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},{"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"} ]
-
批量请求(全是通知):
--> [{"jsonrpc": "2.0", "method": "notify_sum", "params": [1,2,4]},{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]} ] <-- // 所有通知批量没有返回内容
8 扩展
以 rpc. 开头的方法名称是为系统扩展保留的,必须避免用于其他目的。每个系统扩展在相关规范中定义。所有系统扩展都是可选的。