1. 项目概述当 FastAPI 遇上 JSON-RPC如果你正在用 Python 构建微服务或者需要为前端、移动端提供一个结构清晰、文档完备的 API那么FastAPI大概率是你的首选框架。它基于类型提示自动生成 OpenAPI 文档开发体验极佳。但有时候业务场景会更复杂你需要一个支持批量调用、有严格错误码规范、并且客户端调用方式更“过程化”的接口。这时候标准的 RESTful 风格可能就显得有些力不从心而JSON-RPC 2.0协议的优势就凸显出来了。fastapi-jsonrpc这个库正是为了解决这个痛点而生。它不是一个全新的框架而是巧妙地构建在 FastAPI 和 StarletteASGI之上让你能用编写 FastAPI 路由一样熟悉的方式去定义 JSON-RPC 方法。最吸引人的是你无需牺牲任何 FastAPI 的优良特性依赖注入系统Depends、请求验证Body,Header,Cookie、Pydantic 模型以及最重要的——自动生成的 OpenAPI/Swagger UI 文档。它把这些能力无缝地嫁接到了 JSON-RPC 的世界里。简单来说这个库让你鱼与熊掌可以兼得既享受 JSON-RPC 在批量操作和结构化错误处理上的协议优势又保留了 FastAPI 极致的开发效率和现代化的类型安全。对于需要同时提供 RESTful 和 RPC 接口或者希望内部服务间采用更规范 RPC 通信的项目这是一个非常优雅的解决方案。2. 核心设计思路与架构解析2.1 为什么选择 JSON-RPC 2.0在深入代码之前我们先聊聊为什么会在 RESTful 大行其道的今天考虑 JSON-RPC。REST 的核心是资源操作围绕 HTTP 动词GET, POST, PUT, DELETE展开。这在管理实体如用户、文章时非常直观。然而当你的 API 代表的更多是“动作”或“过程”而非对某个资源的增删改查时REST 的语义就会变得有些别扭。例如一个“发送验证码”的接口用 REST 你可能需要设计成POST /sms/verification-code而用 JSON-RPC它就是一个名为send_verification_code的方法参数直接传递。JSON-RPC 2.0 协议定义了一个轻量级的远程过程调用规范所有请求都是 POST主体是一个 JSON 对象包含jsonrpc固定为”2.0″、method方法名、params参数和id请求ID。响应同样是一个 JSON 对象包含result成功结果或error错误对象。它的核心优势在于方法导向API 直接映射到函数/方法对于复杂的业务逻辑接口设计更自然。批量请求单个 HTTP 请求可以包含多个 JSON-RPC 调用服务器会顺序执行并返回一个结果数组这对前端需要同时获取多块数据的场景性能提升显著。结构化错误错误响应有固定的格式code,message,data并且fastapi-jsonrpc支持用 Pydantic 模型来定义data的结构使得错误信息的传递既规范又灵活。通知可以发送没有id的请求服务器执行方法但不返回任何结果适用于日志、审计等场景。fastapi-jsonrpc的设计哲学不是替代 FastAPI而是扩展它。它利用 FastAPI 的底层 ASGI 兼容性和依赖注入系统创建了一个新的“入口点”Entrypoint这个入口点本身就是一个 FastAPI 路由。所有发送到这个路由的请求都会被库的中间件解析为 JSON-RPC 请求然后分派到对应的、由你定义的“方法”上。这些方法在定义时几乎使用了和 FastAPI 路由装饰器app.post一样的语法和组件。2.2 核心组件与工作流理解这个库关键要抓住三个核心类API、Entrypoint和method装饰器。jsonrpc.API()这是你的主要应用实例它是fastapi.FastAPI的子类。这意味着它拥有 FastAPI 应用的所有属性和方法。你可以在它上面添加普通的路由、中间件、后台任务等等。它是所有功能的容器。jsonrpc.Entrypoint(‘/api/rpc’)你可以把它想象成一个专用于处理 JSON-RPC 请求的“路由器”或“命名空间”。一个应用可以绑定多个入口点例如/api/v1/jsonrpc,/api/internal/jsonrpc。每个入口点管理一组属于自己的 RPC 方法。entrypoint.method()这是用于注册 RPC 方法的装饰器。被它装饰的普通 Python 函数就变成了一个 JSON-RPC 方法。装饰器参数可以指定错误类型、摘要、描述等这些信息最终会体现在自动生成的 OpenAPI 和 OpenRPC 文档中。工作流程如下客户端发送一个 POST 请求到Entrypoint绑定的路径如/api/v1/jsonrpc。请求体是一个符合 JSON-RPC 2.0 的 JSON。fastapi-jsonrpc的中间件拦截请求解析出method字段。在对应的Entrypoint中查找注册的方法。利用 FastAPI 的依赖注入和参数解析系统将 JSON-RPC 请求的params映射到 Python 函数的参数上支持通过Body()等指定参数来源。执行函数捕获异常。如果发生错误且错误类型在方法装饰器的errors列表中则按照 JSON-RPC 错误格式和定义的DataModel序列化错误。将结果或错误封装成 JSON-RPC 响应返回给客户端。这个设计确保了从 HTTP 请求到 Python 函数执行的转换是类型安全且高度可定制的。3. 从零开始环境搭建与基础用法3.1 安装与最小化示例安装非常简单使用 pip 即可。建议在虚拟环境中进行。pip install fastapi-jsonrpc库的核心依赖是fastapi和pydantic它们会被自动安装。下面我们来复现并详细解读官方的最小示例这是理解一切的基础。# main.py import fastapi_jsonrpc as jsonrpc from pydantic import BaseModel from fastapi import Body # 1. 创建应用实例它就是一个加强版的 FastAPI 应用 app jsonrpc.API() # 2. 创建一个 JSON-RPC 入口点绑定到路径 /api/v1/jsonrpc api_v1 jsonrpc.Entrypoint(/api/v1/jsonrpc) # 3. 定义自定义错误类型 class MyError(jsonrpc.BaseError): CODE 5000 # 应用特定的错误码不能是标准保留码-32768 到 -32000 MESSAGE My error # 错误概要信息 # 错误附加数据模型可以传递更详细的错误信息 class DataModel(BaseModel): details: str # 4. 使用装饰器注册一个 JSON-RPC 方法 # errors 参数声明此方法可能抛出的、需要被规范处理的错误类型 api_v1.method(errors[MyError]) def echo( data: str Body(..., examples[hello]) # 使用 FastAPI 的 Body 定义参数 ) - str: # 类型注解会同时用于验证和生成文档 一个简单的回声方法。 如果传入的数据是 error则抛出自定义错误。 if data error: # 抛出错误时传入的字典必须符合 DataModel 的定义 raise MyError(data{details: boom}) return data # 5. 将入口点绑定到应用上 app.bind_entrypoint(api_v1) # 6. 使用 Uvicorn 运行应用 if __name__ __main__: import uvicorn uvicorn.run(main:app, port5000, reloadTrue, access_logFalse)运行这个应用后你会得到几个关键的端点POST http://127.0.0.1:5000/api/v1/jsonrpc你的 JSON-RPC 端点。你可以用 curl、Postman 或任何 HTTP 客户端调用它。GET http://127.0.0.1:5000/docs自动生成的 Swagger UI 文档。神奇的是它会将你的 JSON-RPC 方法echo展示为一个标准的 API 接口并允许你在线测试。GET http://127.0.0.1:5000/openapi.jsonOpenAPI 规范文档。GET http://127.0.0.1:5000/openrpc.jsonOpenRPC 规范文档一个专门为 JSON-RPC API 设计的文档规范。3.2 发起你的第一个 JSON-RPC 调用让我们用curl来测试一下上面的echo方法。成功调用curl -X POST http://127.0.0.1:5000/api/v1/jsonrpc \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 1, method: echo, params: {data: hello world} }预期的响应会是{ jsonrpc: 2.0, id: 1, result: hello world }触发自定义错误curl -X POST http://127.0.0.1:5000/api/v1/jsonrpc \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 2, method: echo, params: {data: error} }响应会包含我们定义的错误结构和数据{ jsonrpc: 2.0, id: 2, error: { code: 5000, message: My error, data: { details: boom } } }无效方法调用如果你调用一个未注册的方法库会返回标准的 JSON-RPC 错误{ jsonrpc: 2.0, id: 3, error: { code: -32601, message: Method not found } }注意在 Swagger UI (/docs) 中测试时界面是 RESTful 风格的。你需要填写请求体为一个完整的 JSON-RPC 请求对象而不是直接填params。这是 Swagger UI 的展示方式实际网络传输的仍然是标准的 JSON-RPC 协议。4. 进阶特性与实战技巧4.1 充分利用 FastAPI 生态这是fastapi-jsonrpc最强大的地方。你可以在 JSON-RPC 方法中使用几乎所有 FastAPI 的特性。依赖注入 (Depends)和 FastAPI 路由一样你可以使用Depends来注入依赖比如数据库会话、认证信息、权限检查等。from fastapi import Depends from .database import get_db_session from .auth import get_current_user api_v1.method() def get_my_profile( user: dict Depends(get_current_user), # 依赖注入当前用户 session Depends(get_db_session) # 依赖注入数据库会话 ) - dict: # 直接从依赖中获取 user 和 session无需在参数中手动解析 profile session.query(UserProfile).filter_by(user_iduser[id]).first() return profile.dict()复杂的参数与模型你可以使用 Pydantic 模型来定义复杂的输入参数FastAPI 会自动进行验证和文档生成。from pydantic import BaseModel, Field class ItemCreateModel(BaseModel): name: str Field(..., min_length1, max_length100, description商品名称) price: float Field(..., gt0, description价格必须大于0) tags: list[str] [] api_v1.method() def create_item(item: ItemCreateModel) - dict: # item 已经是一个验证过的 Pydantic 模型实例 new_item Item(**item.dict()) db.session.add(new_item) db.session.commit() return {id: new_item.id, **item.dict()}在 JSON-RPC 请求中你需要将模型数据放在params里。对于单个模型参数通常将其作为params的直接值或命名参数传递。库的默认行为支持像 FastAPI 一样的灵活解析。Header、Cookie 等参数虽然 JSON-RPC 规范本身不涉及 HTTP 头但fastapi-jsonrpc允许你通过 FastAPI 的Header,Cookie,Path,Query来获取这些信息它们会从 HTTP 请求的对应部分提取。from fastapi import Header api_v1.method() def method_need_auth( x_user_token: str Header(None, aliasX-User-Token) ) - str: if not x_user_token: raise AuthError(data{reason: Missing token}) # ... 验证 token return Authenticated4.2 错误处理的艺术fastapi-jsonrpc的错误处理是其一大亮点。它强制你对错误进行类型化定义这使得 API 的错误契约非常清晰。定义错误层级你可以像定义异常类一样定义错误并形成层级结构。class AppError(jsonrpc.BaseError): 应用基础错误 CODE 5000 MESSAGE Application error class ValidationError(AppError): CODE 5001 MESSAGE Validation failed class DataModel(BaseModel): field: str reason: str class DatabaseError(AppError): CODE 5002 MESSAGE Database operation failed class DataModel(BaseModel): operation: str detail: str api_v1.method(errors[ValidationError, DatabaseError]) def update_item(item_id: int, data: dict): if not data.get(name): raise ValidationError(data{field: name, reason: required}) try: # 数据库操作 ... except SomeDBError as e: raise DatabaseError(data{operation: update, detail: str(e)})在文档中展示错误在 Swagger UI 和 OpenRPC 文档中每个方法下方都会明确列出它可能返回的错误码和数据结构这对客户端开发者极其友好。处理未声明的错误如果一个错误被抛出但没有在方法的errors列表中声明它会被捕获并转换为一个通用的JSON-RPC 2.0内部错误code -32603消息为 “Internal error”。这可以防止意外的内部细节泄露。在生产环境中你应该结合日志记录如 Sentry来追踪这些未声明的错误。4.3 批量请求与通知批量请求这是 JSON-RPC 的一个杀手级特性。客户端可以将多个方法调用打包进一个 JSON 数组发送。服务器会按顺序执行每一个调用并返回一个结果数组顺序与请求一一对应。# 假设我们已经定义了 add 和 multiply 方法 # 单个请求体 [ {jsonrpc: 2.0, method: add, params: [1, 2], id: 1}, {jsonrpc: 2.0, method: multiply, params: [3, 4], id: 2}, {jsonrpc: 2.0, method: subtract, params: [10, 5], id: 3} ]服务器会返回[ {jsonrpc: 2.0, id: 1, result: 3}, {jsonrpc: 2.0, id: 2, result: 12}, {jsonrpc: 2.0, id: 3, error: {code: -32601, message: Method not found}} ]注意批量请求中某个调用的失败不会影响其他调用的执行。这对于前端页面初始化时需要加载多个独立数据块的场景能有效减少 HTTP 请求数量提升性能。通知通知是一种没有id字段的请求。服务器会处理方法但不会返回任何响应。这适用于日志记录、审计、触发后台任务等不需要确认结果的场景。{jsonrpc: 2.0, method: log_activity, params: {action: user_login, user_id: 123}}发送这个请求后服务器会执行log_activity方法但客户端不会收到任何回复HTTP 响应体为空。实操心得批量请求虽然强大但需要谨慎使用。要确保批量中的方法都是幂等的或没有副作用依赖顺序因为服务器执行顺序虽然固定但理论上可以并行化。对于有写操作的方法放在批量请求中需要额外考虑事务问题。5. 项目配置、中间件与集成5.1 应用配置与多入口点一个jsonrpc.API()实例可以绑定多个Entrypoint这可以用来做 API 版本隔离或不同服务粒度的区分。app jsonrpc.API() # 公共 API 入口点 public_api jsonrpc.Entrypoint(/api/v1/jsonrpc) # 内部管理 API 入口点路径不同可能还有不同的认证 admin_api jsonrpc.Entrypoint(/api/admin/jsonrpc) # 为不同入口点注册方法 public_api.method() def public_method(): ... admin_api.method() def admin_method(): ... # 绑定到同一个应用 app.bind_entrypoint(public_api) app.bind_entrypoint(admin_api)你还可以在创建API或Entrypoint时传递元数据这些信息会出现在 OpenAPI 和 OpenRPC 文档中。app jsonrpc.API( titleMy JSON-RPC Service, version1.0.0, description一个基于 FastAPI 的 JSON-RPC 微服务, ) api_v1 jsonrpc.Entrypoint( /api/v1/jsonrpc, summaryAPI v1, description第一版 JSON-RPC 接口包含核心业务方法。, )5.2 中间件fastapi-jsonrpc支持上下文管理器风格的中间件这让你可以在方法执行前后注入逻辑例如日志记录、指标收集、超时控制等。中间件可以应用在全局API级别或单个入口点级别。定义一个简单的日志中间件import time import logging from contextlib import contextmanager from fastapi_jsonrpc import BaseMiddleware logger logging.getLogger(__name__) class TimingMiddleware(BaseMiddleware): contextmanager def handle(self, request, response): start_time time.perf_counter() try: yield # 在这里实际的 RPC 方法会被执行 finally: duration time.perf_counter() - start_time method_name request.method if request else unknown logger.info(fJSON-RPC method {method_name} took {duration:.3f}s) # 应用到入口点 api_v1 jsonrpc.Entrypoint(/api/v1/jsonrpc, middlewares[TimingMiddleware()]) # 或者应用到全局 app jsonrpc.API(middlewares[TimingMiddleware()])内置的 Sentry 集成库提供了一个开箱即用的 Sentry 集成可以自动捕获 JSON-RPC 错误并发送到 Sentry。import sentry_sdk from fastapi_jsonrpc.contrib.sentry import FastApiJsonRPCIntegration sentry_sdk.init( dsnYOUR_SENTRY_DSN, integrations[FastApiJsonRPCIntegration()], ) # 之后所有未捕获的、或在方法 errors 列表中声明的错误都会被 Sentry 记录。5.3 测试使用 Pytest 插件fastapi-jsonrpc提供了一个 Pytest 插件使得测试 JSON-RPC 方法就像测试普通函数一样简单并且能很好地捕获和断言 JSON-RPC 错误。首先确保你的pytest版本较新并在项目中安装pytest-asyncio如果使用异步方法。库的插件会自动注册。编写一个测试# test_my_api.py import pytest from fastapi.testclient import TestClient from .main import app, MyError # 导入你的应用和错误类 client TestClient(app) def test_echo_success(): 测试成功的 echo 调用 response client.post( /api/v1/jsonrpc, json{ jsonrpc: 2.0, id: 1, method: echo, params: {data: test} } ) assert response.status_code 200 result response.json() assert result[result] test assert result[id] 1 def test_echo_error(): 测试触发自定义错误 response client.post( /api/v1/jsonrpc, json{ jsonrpc: 2.0, id: 2, method: echo, params: {data: error} } ) assert response.status_code 200 # JSON-RPC 错误仍然是 HTTP 200 error response.json()[error] assert error[code] MyError.CODE assert error[message] MyError.MESSAGE assert error[data][details] boom # 使用 jsonrpc 夹具进行更简洁的测试 def test_echo_with_fixture(jsonrpc): # jsonrpc 是插件提供的夹具 # 它会自动处理请求的封装 result jsonrpc(echo, datahello) assert result hello # 测试错误使用 pytest.raises 并匹配错误类 with pytest.raises(MyError) as exc_info: jsonrpc(echo, dataerror) assert exc_info.value.data {details: boom}要使用jsonrpc夹具你可能需要在conftest.py中配置入口点。# conftest.py import pytest from fastapi.testclient import TestClient from .main import app, api_v1 pytest.fixture def jsonrpc(): client TestClient(app) def _jsonrpc(method, **params): resp client.post(api_v1.path, json{ jsonrpc: 2.0, id: 1, method: method, params: params }) resp.raise_for_status() body resp.json() if error in body: # 这里需要根据错误码映射回异常类简化示例 raise ValueError(body[error]) return body[result] return _jsonrpc6. 生产环境部署与性能调优6.1 部署考量由于fastapi-jsonrpc基于 FastAPI 和 Starlette其部署方式与标准的 FastAPI 应用完全一致。推荐使用uvicorn或hypercorn作为 ASGI 服务器。使用 Gunicorn 管理 Uvicorn Worker经典方案# 安装 pip install uvicorn gunicorn # 使用 gunicorn 启动使用 uvicorn 的 worker 类 gunicorn main:app \ -w 4 \ # 工作进程数通常为 CPU 核心数 * 2 1 -k uvicorn.workers.UvicornWorker \ --bind 0.0.0.0:8000 \ --access-logfile - \ --error-logfile -使用现代部署工具对于容器化部署你可以直接运行uvicorn或者使用像FastAPI官方推荐的uvicorn配合asgi-tools等。在 Dockerfile 中CMD 可以很简单CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000, --proxy-headers]6.2 性能与监控性能特点fastapi-jsonrpc本身只是薄薄的一层封装性能开销极小。主要的性能瓶颈通常在于你的业务逻辑数据库查询、外部 API 调用、复杂计算。JSON 序列化/反序列化对于非常大的请求/响应体这是一个考虑点。确保使用像orjson这样的高性能 JSON 库FastAPI 默认支持。依赖注入复杂的依赖树可能会增加请求处理时间。确保依赖项是高效的并考虑使用缓存。你可以通过设置app jsonrpc.API(default_response_classORJSONResponse)来使用orjson以提升性能。监控日志确保配置了结构化日志如 JSON 格式方便接入 ELK 或 Loki 等日志系统。在中间件中记录请求 ID、方法名、耗时、错误等信息。指标使用像prometheus-client这样的库在中间件中暴露指标如请求次数、方法调用次数、错误次数、请求延迟分布等。这些指标可以被 Prometheus 抓取并在 Grafana 中展示。分布式追踪在微服务架构中集成 OpenTelemetry 或 Jaeger 来追踪一个请求跨多个服务的完整路径。6.3 安全最佳实践认证与授权务必在依赖项Depends中实现严格的认证和授权逻辑。对于 JSON-RPC常见的做法是在 HTTP 头如Authorization: Bearer token中传递令牌然后在依赖项中验证。输入验证充分利用 Pydantic 模型进行输入验证。这是防止恶意或畸形数据的第一道防线。速率限制在入口点或全局应用中间件中实现速率限制防止滥用。可以使用slowapi或fastapi-limiter等库。错误信息在生产环境中确保未声明的内部错误code -32603返回的消息是通用的避免泄露堆栈信息或内部细节。详细的错误应记录到服务端日志中。HTTPS务必使用 HTTPS。这可以在反向代理如 Nginx, Traefik层面实现。7. 常见问题与排查技巧实录在实际使用中你可能会遇到一些典型问题。下面是我在项目中积累的一些排查经验。7.1 问题Swagger UI 中测试接口返回 “Internal Server Error”但直接 curl 调用正常。排查思路检查 Swagger UI 的请求体格式Swagger UI 默认生成的请求体可能不是完整的 JSON-RPC 请求格式。它可能只发送了params部分而缺少外层的jsonrpc,method,id字段。你需要手动在 Swagger UI 的请求体编辑框中输入完整的 JSON-RPC 对象。查看服务器日志在开发服务器uvicorn的日志中会打印出详细的错误信息包括验证错误。这能帮你快速定位问题。确认方法名确保在 Swagger UI 的 “Try it out” 环节你调用的路径是正确的即你的入口点路径并且请求体中的method字段与方法定义的名字完全一致大小写敏感。7.2 问题自定义错误没有被正确捕获总是返回 code -32603 “Internal error”。排查步骤检查错误类定义确保你的错误类继承自jsonrpc.BaseError并且正确设置了CODE和MESSAGE类属性。检查装饰器在api_v1.method(errors[...])中是否将你的错误类添加到了errors列表中。这是一个常见的疏忽点。检查错误抛出方式确保你是raise MyError(data...)并且传入的data字典符合你定义的DataModel结构。如果结构不匹配在开发模式下可能会引发另一个验证错误导致最终返回内部错误。启用调试在开发时可以暂时将未捕获的异常详细信息返回帮助定位。但生产环境切记关闭。app jsonrpc.API(debugTrue) # 仅在开发环境使用7.3 问题使用依赖注入时依赖项无法正常工作如获取不到请求头。原因与解决JSON-RPC 方法的参数解析虽然复用 FastAPI 的机制但上下文略有不同。确保你的依赖项函数签名正确并且期望的参数如Request,Header是合理的。一个常见的坑是依赖项中如果试图从Request中直接读取 JSON 体可能会遇到问题因为请求体可能已经被fastapi-jsonrpc中间件读取并解析了。最佳实践是依赖项尽量用于认证、数据库会话等不直接依赖请求体具体内容params的逻辑。业务参数应通过方法参数传入。7.4 问题批量请求中部分成功部分失败如何确保事务方案JSON-RPC 规范不处理跨方法的事务。如果你的批量操作需要原子性要么全成功要么全回滚你有两个选择设计一个复合方法创建一个新的 JSON-RPC 方法如batch_create_items在这个方法内部实现事务逻辑。这牺牲了批量请求的通用性但保证了事务。在中间件中实现补偿逻辑这是一个更复杂的方案。你可以创建一个中间件在批量请求开始前启动一个数据库事务在每个方法执行后记录其逆操作。如果某个方法失败则执行前面所有成功方法的逆操作进行补偿。这需要业务方法的设计支持幂等和补偿操作。对于大多数场景如果批量操作中的方法是独立的那么使用标准批量请求即可。如果有关联则推荐方案一。7.5 性能排查清单当感觉性能不佳时可以按以下清单检查[ ]数据库查询是否使用了 N1 查询是否缺少必要的索引可以使用 SQLAlchemy 的echoTrue或 Django Debug Toolbar 查看查询。[ ]JSON 序列化返回的 Pydantic 模型是否包含大量不需要的字段或复杂嵌套考虑使用response_model或exclude参数精简响应。[ ]依赖项缓存使用lru_cache或cachetools缓存那些计算昂贵但纯净的依赖项结果。[ ]中间件顺序检查中间件链确保日志、监控等轻量级中间件在前重量级操作在后。[ ]服务器配置Uvicorn/Gunicorn 的 worker 数量是否与 CPU 核心数匹配是否启用了合适的 worker 类如uvicorn.workers.UvicornH11Workerfastapi-jsonrpc作为一个桥梁将 FastAPI 的现代 Web 开发体验与 JSON-RPC 的协议优势结合得相当出色。它尤其适合内部微服务通信、需要强类型契约和批量操作的前后端交互以及那些认为 RESTful 资源模型不太贴合实际业务过程的场景。它的学习曲线非常平缓只要你熟悉 FastAPI就能立刻上手。在实际项目中从清晰的错误定义到自动生成的交互式文档它带来的开发效率和维护性的提升是实实在在的。如果你正在寻找一个 Python 生态下成熟、优雅的 JSON-RPC 解决方案它绝对值得你投入时间深入了解。