1. JsonRPC协议的本质解析
JsonRPC是一种轻量级的远程过程调用(RPC)协议,它使用JSON格式进行数据编码。与传统的REST API相比,JsonRPC具有更明确的请求-响应语义和更灵活的方法调用方式。在前后台架构中,JsonRPC通过HTTP协议传输,但不同于RESTful接口的"资源"概念,它直接暴露可调用的方法。
协议的核心规范其实非常简单:
- 请求体必须包含三个基本字段:
jsonrpc(版本号)、method(方法名)、params(参数) - 响应体必须包含
jsonrpc和result(或error)字段 - 可选的
id字段用于匹配请求和响应
实际开发中常见误区:很多开发者会忽略
jsonrpc:"2.0"的版本声明,虽然看似无关紧要,但某些严格的客户端库会因此拒绝处理请求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 前后台通信架构设计
2.1 基础通信模型
典型的JsonRPC前后台交互流程如下:
mermaid复制sequenceDiagram
participant 前端 as 前端
participant 后端 as 后端
前端->>后端: POST {jsonrpc:"2.0",method:"getUser",params:{id:1},id:1}
后端->>前端: {jsonrpc:"2.0",result:{name:"张三"},id:1}
实际实现时需要特别注意:
- 必须使用POST方法(虽然规范未强制要求,但这是行业惯例)
- Content-Type应设为
application/json - 建议统一API入口(如
/api/jsonrpc)
2.2 批量请求处理
JsonRPC 2.0支持批量请求,这是其重要优势之一:
javascript复制// 请求示例
[
{"jsonrpc":"2.0","method":"getUser","params":[1],"id":1},
{"jsonrpc":"2.0","method":"getPosts","params":{"userId":1},"id":2}
]
// 响应示例
[
{"jsonrpc":"2.0","result":{"name":"张三"},"id":1},
{"jsonrpc":"2.0","result":[/* 文章列表 */],"id":2}
]
性能提示:批量请求可以显著减少HTTP往返次数,但要注意避免单次请求数据过大。建议控制在10个方法调用以内。
3. 服务端实现详解
3.1 Node.js实现方案
以下是基于Express的完整实现:
javascript复制const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
const methods = {
add: ([a, b]) => a + b,
getUser: ({id}) => ({id, name: '测试用户'})
};
app.post('/api', (req, res) => {
const {jsonrpc, method, params, id} = req.body;
if (jsonrpc !== '2.0') {
return res.json({
jsonrpc: '2.0',
error: {code: -32600, message: 'Invalid Request'},
id: null
});
}
if (!methods[method]) {
return res.json({
jsonrpc: '2.0',
error: {code: -32601, message: 'Method not found'},
id
});
}
try {
const result = methods[method](params);
res.json({jsonrpc: '2.0', result, id});
} catch (e) {
res.json({
jsonrpc: '2.0',
error: {code: -32603, message: e.message},
id
});
}
});
app.listen(3000);
关键点说明:
- 错误处理必须遵循规范定义的错误码(-32600到-32603)
- 参数校验应该放在方法实现内部
- 建议对method做白名单控制
3.2 Python实现方案
使用jsonrpcserver库可以快速搭建服务端:
python复制from jsonrpcserver import method, serve
@method
def add(a, b):
return a + b
@method
def getUser(id):
return {"id": id, "name": "测试用户"}
if __name__ == "__main__":
serve(port=5000)
4. 客户端实现方案
4.1 JavaScript客户端
推荐使用jayson库:
javascript复制const jayson = require('jayson');
const client = jayson.Client.http({
hostname: 'localhost',
port: 3000
});
// 单次调用
client.request('add', [1, 2], (err, response) => {
if(err) throw err;
console.log(response.result); // 3
});
// 批量调用
client.request([
{method: 'add', params: [1, 2]},
{method: 'getUser', params: {id: 1}}
], (err, responses) => {
// responses是数组
});
4.2 浏览器端直接调用
如果不依赖库,可以直接使用fetch:
javascript复制async function j
