吐血整理JSON-RPC2.0的原理与应用
吐血整理JSON-RPC2.0的原理与应用作为一名全栈工程师我在日常开发中经常需要处理不同服务之间的远程调用问题。从RESTful API到gRPC再到WebSocket每种协议都有自己的适用场景。但有一个协议它轻量、跨语言、且天然支持异步调用那就是JSON-RPC。今天我就从原理到实战彻底讲清楚JSON-RPC 2.0。## 什么是JSON-RPC 2.0JSON-RPC是一种无状态的、轻量级的远程过程调用RPC协议。它使用JSON作为数据格式基于HTTP或TCP等传输层协议工作。JSON-RPC 2.0是目前最广泛使用的版本规范简单清晰非常适合微服务间通信、浏览器扩展、区块链应用如以太坊等场景。核心特性-无状态每次调用都是独立的不依赖上下文-轻量级JSON编码易于解析和生成-支持批量调用一次请求可以发送多个调用-通知机制无需响应的单向消息## 协议规范详解JSON-RPC 2.0的请求对象包含以下字段-jsonrpc必须为2.0-method要调用的方法名字符串-params参数可选可以是数组或对象-id请求标识符可用于匹配响应通知时可为null响应对象包含-jsonrpc必须为2.0-result成功时的返回值成功时必需-error失败时的错误对象失败时必需-id与请求相同的id错误对象包含-code错误码整数-message错误描述字符串-data附加数据可选标准错误码--32700解析错误--32600无效请求--32601方法不存在--32602无效参数--32603内部错误--32000~-32099服务器错误## 实战Python实现一个简单的JSON-RPC服务器下面我用Python从零搭建一个JSON-RPC服务器支持基本调用和错误处理。### 示例1基础JSON-RPC服务器python# json_rpc_server.pyimport jsonfrom http.server import HTTPServer, BaseHTTPRequestHandlerclass JSONRPCHandler(BaseHTTPRequestHandler): # 定义可用方法 methods { add: lambda a, b: a b, subtract: lambda a, b: a - b, echo: lambda msg: msg, divide: lambda a, b: a / b # 注意可能除零错误 } def do_POST(self): # 读取请求体 content_length int(self.headers[Content-Length]) body self.rfile.read(content_length).decode(utf-8) try: request json.loads(body) except json.JSONDecodeError as e: # 处理JSON解析错误 self.send_response(200) self.send_header(Content-Type, application/json) self.end_headers() error_response { jsonrpc: 2.0, error: { code: -32700, message: Parse error, data: str(e) }, id: None } self.wfile.write(json.dumps(error_response).encode()) return # 验证jsonrpc版本 if request.get(jsonrpc) ! 2.0: self.send_response(200) self.send_header(Content-Type, application/json) self.end_headers() error_response { jsonrpc: 2.0, error: {code: -32600, message: Invalid Request}, id: request.get(id, None) } self.wfile.write(json.dumps(error_response).encode()) return method_name request.get(method) params request.get(params, []) request_id request.get(id) # 检查方法是否存在 if method_name not in self.methods: response { jsonrpc: 2.0, error: {code: -32601, message: fMethod {method_name} not found}, id: request_id } else: try: # 调用方法 if isinstance(params, list): result self.methods[method_name](*params) elif isinstance(params, dict): result self.methods[method_name](**params) else: result self.methods[method_name]() response { jsonrpc: 2.0, result: result, id: request_id } except Exception as e: # 捕获运行时错误 response { jsonrpc: 2.0, error: {code: -32603, message: Internal error, data: str(e)}, id: request_id } self.send_response(200) self.send_header(Content-Type, application/json) self.end_headers() self.wfile.write(json.dumps(response).encode())if __name__ __main__: server HTTPServer((localhost, 8080), JSONRPCHandler) print(JSON-RPC server running on http://localhost:8080) server.serve_forever()测试命令使用curlbash# 正常调用curl -X POST http://localhost:8080 -H Content-Type: application/json -d {jsonrpc:2.0,method:add,params:[3,5],id:1}# 错误调用方法不存在curl -X POST http://localhost:8080 -H Content-Type: application/json -d {jsonrpc:2.0,method:unknown,params:[],id:2}### 示例2支持批量调用的客户端python# json_rpc_client.pyimport jsonimport requestsclass JSONRPCClient: def __init__(self, endpoint): self.endpoint endpoint def call(self, method, paramsNone, request_id1): 单个RPC调用 :param method: 方法名 :param params: 参数列表或字典 :param request_id: 请求ID :return: 响应结果 payload { jsonrpc: 2.0, method: method, id: request_id } if params is not None: payload[params] params response requests.post(self.endpoint, jsonpayload) response_data response.json() if error in response_data: raise Exception(fRPC Error: {response_data[error]}) return response_data.get(result) def batch_call(self, calls): 批量RPC调用 :param calls: 列表每个元素是(method, params, request_id)元组 :return: 响应列表 batch_payload [] for method, params, request_id in calls: payload { jsonrpc: 2.0, method: method, id: request_id } if params is not None: payload[params] params batch_payload.append(payload) response requests.post(self.endpoint, jsonbatch_payload) response_data response.json() # 返回结果映射按id排序 results {} for item in response_data: if result in item: results[item[id]] item[result] elif error in item: results[item[id]] {error: item[error]} return results def notify(self, method, paramsNone): 发送通知无需响应 :param method: 方法名 :param params: 参数 payload { jsonrpc: 2.0, method: method, params: params } # 通知没有id字段 requests.post(self.endpoint, jsonpayload)# 使用示例if __name__ __main__: client JSONRPCClient(http://localhost:8080) # 单个调用 result client.call(add, [10, 20], 1) print(fadd(10,20) {result}) # 输出: 30 # 使用命名参数 result client.call(subtract, {a: 10, b: 3}, 2) print(fsubtract(10,3) {result}) # 输出: 7 # 批量调用 batch_calls [ (add, [1, 2], 10), (echo, [hello world], 11), (divide, [10, 2], 12), (divide, [10, 0], 13) # 这个会出错 ] results client.batch_call(batch_calls) print(fBatch results: {results}) # 输出: {10: 3, 11: hello world, 12: 5.0, 13: {error: {...}}} # 发送通知 client.notify(echo, [this is a notification])## 高级应用与WebSocket集成在需要实时通信的场景如聊天应用、实时数据推送JSON-RPC与WebSocket结合非常强大。下面是一个基于WebSocket的JSON-RPC实现片段python# websocket_rpc_server.py使用websockets库import asyncioimport jsonimport websocketsclass WebSocketRPCServer: def __init__(self): self.methods { ping: lambda: pong, get_time: lambda: asyncio.get_event_loop().time() } async def handle_message(self, websocket, message): try: request json.loads(message) except json.JSONDecodeError: await websocket.send(json.dumps({ jsonrpc: 2.0, error: {code: -32700, message: Parse error}, id: None })) return method request.get(method) params request.get(params, []) request_id request.get(id) if method in self.methods: try: result self.methods[method](*params) if isinstance(params, list) else self.methods[method](**params) response { jsonrpc: 2.0, result: result, id: request_id } except Exception as e: response { jsonrpc: 2.0, error: {code: -32603, message: str(e)}, id: request_id } else: response { jsonrpc: 2.0, error: {code: -32601, message: Method not found}, id: request_id } await websocket.send(json.dumps(response)) async def handler(self, websocket, path): async for message in websocket: await self.handle_message(websocket, message)# 启动服务器# start_server websockets.serve(WebSocketRPCServer().handler, localhost, 8765)# asyncio.get_event_loop().run_until_complete(start_server)# asyncio.get_event_loop().run_forever()## 应用场景总结JSON-RPC 2.0在实际项目中应用广泛1.微服务通信在Kubernetes集群中服务间调用可以使用JSON-RPC比REST更直接2.区块链以太坊的JSON-RPC接口是开发者与智能合约交互的标准方式3.浏览器扩展Chrome扩展的消息传递机制类似JSON-RPC4.IoT设备轻量级协议适合资源受限设备## 总结JSON-RPC 2.0是一个被低估的协议它的简洁性使其成为很多场景的理想选择。通过本文的代码示例你可以看到- 实现一个JSON-RPC服务器只需要不到100行Python代码- 批量调用可以大幅提升性能减少HTTP连接数- 通知机制适用于日志、监控等单向消息场景- 与WebSocket结合可以实现双向实时通信在实际项目中我建议- 对于内部服务调用优先考虑JSON-RPC而非REST减少HTTP开销- 使用标准的错误码便于客户端统一处理- 注意安全性总是验证请求的jsonrpc字段和参数类型- 考虑使用成熟库如Python的jsonrpcserver、jsonrpcclient减少重复造轮子希望这篇文章能帮你彻底掌握JSON-RPC 2.0并在你的下一个项目中高效使用它。

相关新闻

MCSPI控制器模式详解:从信号定义到实战配置的嵌入式SPI开发指南

MCSPI控制器模式详解:从信号定义到实战配置的嵌入式SPI开发指南

1. MCSPI控制器模式:从信号定义到实战配置的深度解析在嵌入式系统开发中,SPI(Serial Peripheral Interface)几乎是工程师的“必修课”。它简单、高效,是连接传感器、存储器、显示屏等外设的“血管”。但当你从标准SPI转…

2026/10/15 16:38:57 阅读更多 →
TI C2000 MibSPI寄存器深度解析:从引脚控制到数据传输实战

TI C2000 MibSPI寄存器深度解析:从引脚控制到数据传输实战

1. 项目概述与核心价值在嵌入式开发,尤其是基于德州仪器(TI)C2000、Hercules等系列MCU的项目中,SPI(串行外设接口)是连接Flash、传感器、ADC/DAC等外设的“血管”。但很多开发者,尤其是刚接触TI…

2026/10/16 17:27:03 阅读更多 →
ZeroOmega:终极浏览器代理管理解决方案,轻松掌控网络访问

ZeroOmega:终极浏览器代理管理解决方案,轻松掌控网络访问

ZeroOmega:终极浏览器代理管理解决方案,轻松掌控网络访问 【免费下载链接】ZeroOmega Manage and switch between multiple proxies quickly & easily. 项目地址: https://gitcode.com/gh_mirrors/ze/ZeroOmega ZeroOmega是一款强大的开源浏览…

2026/10/15 16:39:01 阅读更多 →

最新新闻

Unreal+AirSim自建仿真闭环:从环境搭建到高保真传感器闭环

Unreal+AirSim自建仿真闭环:从环境搭建到高保真传感器闭环

1. 项目概述:从零搭建一个可交互的UnrealAirSim仿真闭环你有没有试过在电脑里“开飞机”——不是玩《微软模拟飞行》那种消费级游戏,而是用真实飞控逻辑、带物理引擎的气流扰动、毫米级激光雷达点云、甚至能跑ROS节点的完整无人机仿真系统?这…

2026/10/17 11:09:17 阅读更多 →
【芳心科技】基于GSM车窗控制滞留检测系统

【芳心科技】基于GSM车窗控制滞留检测系统

实物效果图:实现功能:该设计可以通过霍尔传感器检测车辆的运行状态,当车辆停止系统会检测车内是否有儿童滞留,通过压力传感器检测驾驶座上驾驶员是否在位,如果驾驶员离去,有儿童滞留且温度和二氧化碳浓度都…

2026/10/17 11:09:17 阅读更多 →
DeepSeek本地部署实战:Ollama + Open WebUI完整部署指南

DeepSeek本地部署实战:Ollama + Open WebUI完整部署指南

DeepSeek本地部署这件事,我前后折腾了小半个月。最开始只是在命令行里敲几行命令跑起来试试,后来渐渐发现Ollama搭配Open WebUI的组合,才是真正适合日常使用的形态。现在这套部署方案已经成为了我每天都会打开的本地服务,聊天、问…

2026/10/17 11:09:17 阅读更多 →
MCP与A2A如何选?从JSON-RPC到Agent协议分层解析

MCP与A2A如何选?从JSON-RPC到Agent协议分层解析

做 Agent 开发的这段时间,几乎每周都会被人问到一个问题:MCP 和 A2A 到底什么关系?我今天接工具该用哪个?为什么 JSON-RPC 活了几十年,大家还不消停,又捣鼓出这么多新协议?这个问题三句话说不清…

2026/10/17 11:09:17 阅读更多 →
Seedance 2.0角色一致性视频生成全解析:从原理到实操

Seedance 2.0角色一致性视频生成全解析:从原理到实操

最近AI视频圈有个名字被反复提起:Seedance 2.0。说实话,刚看到演示片段的时候我第一反应是"又是个花架子",但实际跑过几轮项目之后,我的判断变了。这款工具最离谱的地方不在于它能生成多高质量的视频,而在于…

2026/10/17 11:09:17 阅读更多 →
Claude Code使用:CC配置第三方模型后,内置工具到底用的谁的?TaoToken统一通道实测

Claude Code使用:CC配置第三方模型后,内置工具到底用的谁的?TaoToken统一通道实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 11:08:17 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →