从零开始:一文读懂 JSON-RPC 是什么以及如何使用
引言:现代应用通信的基石
在当今这个由无数微服务、前后端分离、跨平台应用构成的世界里,不同系统组件之间的高效、稳定通信至关重要,我们熟知的 HTTP 协议虽然无处不在,但在许多场景下,它显得有些“笨重”,比如需要发送完整的 HTTP 请求头,响应也包含了大量不必要的 HTTP 元数据。
为了解决这一问题,轻量级的远程过程调用协议应运而生。JSON-RPC (JavaScript Object Notation Remote Procedure Call) 凭借其简洁、高效和跨语言的特点,成为了许多开发者构建 API 和服务间通信的首选工具,本文将带你从零开始,了解 JSON-RPC 是什么,以及如何在实践中使用它。
什么是 JSON-RPC?
JSON-RPC 是一种无状态、轻量级的远程过程调用协议,它允许一台计算机上的程序(客户端)执行另一台计算机上的程序(服务器)上的方法,并接收返回的结果。
它的核心思想非常简单:通过一个 JSON 消息来发起一个“请求”,服务器处理这个请求后,再通过另一个 JSON 消息返回“响应”。
与 REST API 不同,JSON-RPC 不依赖于特定的 HTTP 方法(如 GET, POST)或 URL 路径,它只关心“调用一个方法并得到结果”,这使得它在处理需要频繁、双向通信的应用(如实时协作、游戏服务器、内部微服务调用)时,比 REST 更加高效和专注。
JSON-RPC 的核心工作原理
JSON-RPC 的交互模型非常清晰,遵循一个严格的请求-响应模式。
请求
客户端向服务器发送一个 JSON 对象,这个对象必须包含以下关键字段:
jsonrpc: 协议版本,通常为"2.0"。method: 要调用的方法名称,这是一个字符串。params: 调用方法所需的参数,它是一个数组或对象,如果不需要参数,可以省略或为空数组[]。id: 一个唯一的标识符,用于将请求与响应进行匹配,可以是数字、字符串或null(对于通知请求)。
示例请求:
假设我们想调用一个名为 subtract 的方法,参数是 42 和 23。
{
"jsonrpc": "2.0",
"method": "subtract",
"params": [42, 23],
"id": 1
}
响应
服务器在接收到请求并处理完毕后,会返回一个 JSON 对象作为响应,这个对象包含以下关键字段:
jsonrpc: 协议版本,必须为"2.0"。result: 方法的执行结果,如果方法执行成功,这里就是返回的数据,如果执行失败,此字段不存在。error: 如果方法执行过程中发生错误,这里会包含一个错误对象,如果执行成功,此字段不存在。id: 与请求中id字段完全相同的标识符,用于客户端匹配。
示例成功响应:
对于上面的请求,服务器成功计算出 42 - 23 = 19。
{
"jsonrpc": "2.0",
"result": 19,
"id": 1
}
示例错误响应: 如果参数类型错误,服务器可能会返回如下错误:
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params: '42' is not a string."
},
"id": 1
}
如何使用 JSON-RPC(实践指南)
理解了原理,我们来看看如何在真实项目中使用 JSON-RPC,我们将以一个简单的 Python 服务器和 JavaScript 客户端为例。
场景: 实现一个简单的计算器服务,提供 add(加法)和 getSquare(求平方)方法。
搭建 JSON-RPC 服务器
我们将使用 Python 的 jsonrpcserver 库来快速创建一个服务器。
步骤 1:安装依赖
pip install jsonrpcserver
步骤 2:编写服务器代码
创建一个名为 server.py 的文件:
from jsonrpcserver import method, Success, Result
from jsonrpcserver import config
# 配置服务器在所有网络接口上监听
config.LOGS = False
@method
def add(a: float, b: float) -> Result:
"""加法方法"""
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise ValueError("Parameters must be numbers")
return a + b
@method
def getSquare(number: float) -> Result:
"""求平方方法"""
if not isinstance(number, (int, float)):
raise ValueError("Parameter must be a number")
return number * number
if __name__ == "__main__":
# 启动一个简单的 HTTP 服务器,监听在 8000 端口
from jsonrpcserver import serve
print("Server is running on http://localhost:8000")
serve(host='0.0.0.0', port=8000)
步骤 3:运行服务器 在终端中执行:
python server.py
你的 JSON-RPC 服务器已经在 http://localhost:8000 上运行了。
编写 JSON-RPC 客户端
我们将使用 JavaScript 的 fetch API 来与我们的 Python 服务器通信,你可以直接在浏览器控制台或 Node.js 环境中运行以下代码。
步骤 1:创建一个通用的请求函数 为了避免重复代码,我们先封装一个发送 JSON-RPC 请求的函数。
// 发送 JSON-RPC 请求的通用函数
async function sendJsonRpcRequest(method, params, id = 1) {
const response = await fetch('http://localhost:8000', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: "2.0",
method: method,
params: params,
id: id,
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
步骤 2:调用服务器方法
我们可以使用上面的函数来调用我们的服务了。
调用 add 方法:
// 调用 add(5, 10)
async function callAdd() {
try {
const result = await sendJsonRpcRequest('add', [5, 10], 1);
console.log('Response for add(5, 10):', result);
// 预期输出: { jsonrpc: '2.0', result: 15, id: 1 }
} catch (error) {
console.error('Error:', error);
}
}
callAdd();
调用 getSquare 方法:
// 调用 getSquare(9)
async function callGetSquare() {
try {
const result = await sendJsonRpcRequest('getSquare', [9], 2);
console.log('Response for getSquare(9):', result);
// 预期输出: { jsonrpc: '2.0', result: 81, id: 2 }
} catch (error) {
console.error('Error:', error);
}
}
callGetSquare();
处理错误情况:
// 调用 add 方法并传入非数字参数
async function callAddWithError() {
try {
const result = await sendJsonRpcRequest('add', ['hello', 10], 3);
console.log('Response for add("hello", 10):', result);
} catch (error) {
console.error('Error:', error);
}
}
callAddWithError();
服务器会返回一个错误对象,客户端可以根据 error 字段来处理异常。
JSON-RPC vs. REST API
| 特性 | JSON-RPC | REST API |
|---|---|---|
| 核心思想 | 过程调用(RPC) | 资源导向 |
| 通信模式 | 请求-响应 | 无状态,客户端驱动 |
| HTTP 方法 | 不依赖,通常只用 POST | 依赖 (GET, POST, PUT, DELETE 等) |
| URL 设计 | 通常固定,不体现方法名 | URL 代表资源 (e.g., /users/123) |
| 数据格式 | 严格使用 JSON | 可以是 JSON, XML, HTML 等 |
| 适用场景 | 服务间通信、实时应用、需要频繁调用的场景 | 公开 API、Web 应用、CRUD 操作为主的场景 |
- 用 REST 当你是在操作



还没有评论,来说两句吧...