firemail

标题: JSON-RPC是什么 [打印本页]

作者: Qter    时间: 2024-10-31 19:50
标题: JSON-RPC是什么
JSON-RPC 是一个基于 JSON 的轻量级远程过程调用(RPC)协议。让我详细解释它的核心概念和使用方式:

1. 基本格式:

```javascript
// 请求格式
{
    "jsonrpc": "2.0",    // 协议版本,固定为 "2.0"
    "method": "subtract", // 要调用的方法名
    "params": [42, 23],   // 参数,可以是数组或对象
    "id": 1              // 请求标识符,用于匹配响应
}

// 响应格式(成功)
{
    "jsonrpc": "2.0",
    "result": 19,        // 结果
    "id": 1             // 对应请求的id
}

// 响应格式(错误)
{
    "jsonrpc": "2.0",
    "error": {
        "code": -32600,  // 错误码
        "message": "Invalid Request" // 错误信息
    },
    "id": 1
}
```

2. 通知(Notification):
```javascript
// 通知是不需要响应的请求,没有 id 字段
{
    "jsonrpc": "2.0",
    "method": "update",
    "params": [1, 2, 3, 4, 5]
}
```

3. 批量请求:
```javascript
// 多个请求可以打包在一个数组中发送
[
    {
        "jsonrpc": "2.0",
        "method": "sum",
        "params": [1, 2, 3],
        "id": 1
    },
    {
        "jsonrpc": "2.0",
        "method": "multiply",
        "params": [4, 5],
        "id": 2
    }
]

// 批量响应
[
    {
        "jsonrpc": "2.0",
        "result": 6,
        "id": 1
    },
    {
        "jsonrpc": "2.0",
        "result": 20,
        "id": 2
    }
]
```

4. 实际应用示例(以 Motrix/aria2 为例):

```javascript
// 客户端实现
class JsonRpcClient {
    constructor(url) {
        this.url = url;
        this.id = 0;
    }

    async call(method, params) {
        const request = {
            jsonrpc: "2.0",
            method: method,
            params: params,
            id: ++this.id
        };

        const response = await fetch(this.url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(request)
        });

        return response.json();
    }
}

// 使用示例
const client = new JsonRpcClient('http://localhost:16800/jsonrpc');

// 添加下载任务
await client.call('aria2.addUri', [
    ['http://example.com/file.zip']
]);

// 查询下载状态
const status = await client.call('aria2.tellStatus', ['gid123']);
```

5. 错误处理:
```javascript
// 预定义的错误码
const ERROR_CODES = {
    PARSE_ERROR: -32700,     // 解析错误
    INVALID_REQUEST: -32600, // 无效请求
    METHOD_NOT_FOUND: -32601, // 方法不存在
    INVALID_PARAMS: -32602,  // 无效参数
    INTERNAL_ERROR: -32603   // 内部错误
};

// 错误处理示例
try {
    const result = await client.call('nonexistentMethod', []);
} catch (error) {
    if (error.code === -32601) {
        console.error('Method not found');
    }
}
```

6. WebSocket 实现:
```javascript
class JsonRpcWebSocketClient {
    constructor(url) {
        this.ws = new WebSocket(url);
        this.id = 0;
        this.callbacks = new Map();

        this.ws.onmessage = (event) => {
            const response = JSON.parse(event.data);
            // 处理响应
            if (response.id && this.callbacks.has(response.id)) {
                const callback = this.callbacks.get(response.id);
                this.callbacks.delete(response.id);
                callback(response.error, response.result);
            }
            // 处理通知
            else if (!response.id) {
                this.handleNotification(response);
            }
        };
    }

    call(method, params) {
        return new Promise((resolve, reject) => {
            const id = ++this.id;

            this.callbacks.set(id, (error, result) => {
                if (error) reject(error);
                else resolve(result);
            });

            this.ws.send(JSON.stringify({
                jsonrpc: "2.0",
                method: method,
                params: params,
                id: id
            }));
        });
    }

    handleNotification(notification) {
        // 处理服务器推送的通知
        console.log('Received notification:', notification);
    }
}
```

7. 主要特点:
- 简单易用:使用 JSON 格式,易于理解和调试
- 语言无关:可以在任何支持 JSON 的语言中使用
- 传输协议无关:可以通过 HTTP、WebSocket 等传输
- 支持双向通信:通过通知机制支持服务器推送
- 支持批量操作:可以在一个请求中包含多个调用

8. 使用建议:
- 为方法提供明确的命名空间(如 aria2.addUri)
- 合理使用批量请求减少网络往返
- 实现错误重试和超时处理
- 考虑并发请求的处理
- 合理使用通知机制降低服务器负载






欢迎光临 firemail (http://firemail.wang:8088/) Powered by Discuz! X3