JSON-RPC协议详解:从原理到实战的接口通信经验
做后端这几年我和“接口通信”这件事打过太多交道了。不管是给前端提供数据还是服务之间互相调用最绕不开的一个问题就是两个系统之间到底用什么姿势把“我要调用你某个功能”这句话说清楚。有人用 REST有人上 gRPC也有不少人直接在应用层塞一段 JSON 就开干——而 jsonRpc 这个老牌协议就是我实际项目里用的最多的方案之一。它足够轻、足够直接几乎没有学习成本也特别适合那种“我只想调一个服务端函数”的场景。这篇就当是一份完整复盘把我从协议原理到实战踩坑的整套经验整理出来给正在选型或者已经被 jsonRpc 折腾过一把的同学做个参考。不管你是在搞内部微服务、写工具链还是只是想让两个模块之间的调用更干净这篇应该都能对得上你的需求。1. jsonRpc 的核心价值与选型考量1.1 它到底是什么先把这个名词拆开。jsonRpc 全称是 JSON-RPC一种以 JSON 为数据格式的远程过程调用协议目前用的最多的是 2.0 版本。它的思路特别直观客户端把“我想调用哪个函数、传什么参数”打包成一个 JSON 对象发给服务端服务端执行完函数再把结果或错误打包成另一个 JSON 对象返回。整个过程就像本地调用一个函数那样自然只不过这个函数跑在了另一台机器上。一个典型的请求长这样{jsonrpc: 2.0, method: getUserName, params: [1001], id: 1}服务端返回{jsonrpc: 2.0, result: {name: 张三}, id: 1}如果出错了就返回 error 字段而不是 result 字段。请求对象里有个 id用于把响应和请求对上号。这里值得强调的是“rpc”这套东西其实在上世纪七八十年代就有了但 JSON-RPC 因为借助了 JSON 的文本表达力把跨语言、跨平台的调用门槛降到了极低。任何一个语言只要能解析 JSON、能发网络请求就能立刻实现一个 jsonRpc 服务。1.2 为什么我会选它而不是无脑上 REST很多人会问现在 REST 不是已经是事实标准了吗为什么还要用 JSON-RPC我个人的观点不是“谁替代谁”而是不同的场景有不同最合适的方案。REST 擅长的是资源管理围绕 URL 和 HTTP 动词来操作资源。如果你要设计一套公开 API需要对资源做增删改查REST 没问题。但当你面对的是“调用服务端的某个方法”比如让服务端计算一个值、执行一段逻辑REST 就开始别扭了。举个实际例子我早期做某个后台系统的时候需要让客户端通知服务端“触发一次报表生成”。用 REST 的话要么 POST /api/reports把“生成”这个动词用不同粒度拆分要么就得自己发明一些不伦不类的路径。而用 JSON-RPC就是一句话的事{jsonrpc: 2.0, method: report.generate, params: {reportId: 1024}, id: 5}服务端既能明明确确地执行对应逻辑又能在响应里直接拿到结果。调用语义和实现代码一一对应无需为了 RESTful 的“资源”概念做额外设计。这个特点让 jsonRpc 在内部服务之间、前后端一体化的中台系统里用起来极其顺手。1.3 和 gRPC 比优势与短板都在哪gRPC 是另一个重量级选手基于 HTTP/2 Protobuf性能强、强类型、自带流式传输。但 gRPC 的代价也不小要写 .proto 文件要生成客户端和服务端代码要维护一堆生成的代码文件团队没有一定规模这套成本其实有点吃不消。如果是小团队、轻量项目或者跨语言快速联调jsonRpc 的优势就体现出来了服务端只需要一个 HTTP 接口入口或者长连接入口接收 JSON解析后路由到具体方法即可。客户端甚至不需要任何代码生成直接用通用的 HTTP 工具就能调试。比起 gRPC 的强约束jsonRpc 更像是一把“能上手就能用”的瑞士军刀。当然如果未来业务需要双端高并发、大量流式传输、强契约保障那么 gRPC 更合适。这两者并不冲突甚至可以基于同一个服务抽象层对外同时暴露 jsonRpc 和 gRPC 两种入口。这里放一张我经常拿来做决策的对照表维度JSON-RPCRESTgRPC数据格式JSON可读性好JSON 为主Protobuf 二进制调用模型本地函数式调用资源式操作强类型存根调用学习成本极低中中高代码生成无无有流式支持不支持可配合长连接扩展弱强性能中适合业务系统中高适合场景内部系统、工具链、轻量服务对外资源 API大规模微服务、流式通信从这张表也能看出来jsonRpc 从来不是万能的但它在“内部系统函数调用”这个特定场景下确实是一个性价比很高的选择。1.4 适用边界什么情况我劝你别用它作为一个用过不少方案的人我也得坦诚说 jsonRpc 的边界。如果你要做的是公众互联网上的开放平台 API那么建议你还是老老实实做 REST 或者更现代的规范这样对接方的认知成本最低。如果是超大规模微服务团队追求极致性能和服务网格协议生态那 gRPC 更合适。此外如果请求和响应数据动不动就十几 MBJSON 的冗余和解析性能就会成为一个问题。那我在什么场景下会坚定地用 jsonRpc 呢基本是这几类公司内部的管理系统、前后端分离内部接口、物联网网关给上层平台上报数据和下发指令、以及一些“不想引入太重框架”的工具型服务。总结成一句话你想让服务端像一个函数库一样被调用而且想用最小的成本把它跑起来那么 jsonRpc 会是一个相当清爽的选择。2. jsonRpc 协议细节逐项拆解2.1 请求对象的四个关键字段任何一次 jsonRpc 请求核心都在一个 JSON 对象里至少包含四个可控制字段jsonrpc、method、params、id。jsonrpc固定为字符串2.0用来告诉服务端协议版本。method是服务端要调用的方法名。方法名可以自己定义命名规则常见的是用点号分层类似user.getById、order.create。用点号的好处是服务端可以按前缀做权限校验、做路由分组。params是传给方法的参数可以是一个数组按位置传参也可以是一个对象按名称传参。传对象的方式可读性更好而且能避免参数位置写错的问题我后文会详细讲。id是用来关联请求和响应的标识符。里可以放字符串、数字或 null但实际操作中我强烈建议传一个唯一且单调递增的数字别用 null 也别省略否则你没法区分这个响应到底是哪个请求返回的。这里有个细节如果请求没有 id那么这个请求被称为 notification服务端执行后不会返回任何响应。我习惯把它当“只发命令、不需要往回拿结果”的接口来用。2.2 响应对象与 error 的规范响应对象同样是个 JSON 对象。正常情况响应必然包含result出错时响应必然包含error。这两者在同一个响应里互斥出现。error的结构是{ code: -32601, message: Method not found, data: null }协议预定义了一批错误码每个错误码都有明确含义。我平时最常用的几个code含义触发场景-32700解析错误服务端收到无法解析的 JSON-32600无效请求请求 JSON 不是合法对象或字段缺失-32601方法不存在method 指到未注册的函数-32602无效参数params 结构不合法或参数校验失败-32603内部错误服务端执行方法时抛出异常-32000 到 -32099服务端自定义错误业务层错误比如数据不存在、权限不足自定义错误码这一块特别适合做业务层“语义化”。比如我在项目里会统一把“登录态失效”编码成 -32001把“参数校验失败”编码成 -32002这样客户端在通用错误处理逻辑里就能直接根据 code 分支处理不用去解析 message 字符串也不容易踩到“文案变了导致判断失效”这种坑。2.3 通知机制不需要响应的调用刚才提到 notification 是没有 id 的请求。为什么需要这种东西很简单有些调用我们只关心发出去不关心执行结果。最典型的例子就是“日志上报”和“事件通知”。比如客户端批量上报操作日志如果每一条都要等响应既浪费带宽又拖慢主流程。这时候直接发一个没有 id 的 jsonRpc 请求服务端收到了就执行客户端也无须处理响应。再用 RPC 的思路理解这就像一个返回值为 void 的异步函数调用方根本不在乎它的返回结果。不过要提醒一句因为 notification 没有响应如果服务端执行出错客户端是完全感知不到的。所以只有“执行失败不致命”的场景才适合用 notification真正重要的操作还是老老实实带上 id确保能拿到执行结果再做下一步决策。2.4 批量请求一次发多条jsonRpc 2.0 还支持批量操作客户端可以把多个请求放在一个 JSON 数组里发送服务端按顺序执行最后也返回一个数组。这里有一个兼容陷阱如果传入的是一个空数组服务端应该返回一个解析错误因为从语义上“空数组不包含任何请求”属于无效请求。批量请求在执行时服务端会为每个请求单独生成对应响应并且响应数组里的每一项都会带上原请求的 id。如果单个请求本身就是 notification那么该请求在返回数组里就没有对应项。这个机制在处理“一批状态更新”的时候特别有用能显著减少 HTTP 交互次数但服务端实现时要特别注意处理顺序和部分失败的组合逻辑这点我在后面排查章节会展开讲。3. 从零实现一套 jsonRpc 服务3.1 技术选型与工程结构协议讨论完了接下来就是动手环节。我选 Python 标准库来做一版最小实现这样没有第三方依赖任何机器装了 Python 就能跑能最大限度展示 jsonRpc 本身的逻辑。更复杂项目里我也会用类似框架但底层的这套路由和错误处理思想是通用的。先想清楚服务端需要干几件事暴露一个 HTTP 入口接收 POST 请求。读 body解析成 JSON。判断是单个请求还是批量数组。校验jsonrpc字段和method字段。从注册表找到对应的方法并调用。捕获异常并统一转成协议错误响应。序列化结果返回给客户端。基于这个流程我通常会把工程拆成三个文件protocol.py负责错误码和异常定义server.py负责路由和分发client.py封装客户端请求逻辑。这种拆分的好处是以后如果要加鉴权、加日志都有明确的位置可以插进去。3.2 错误对象与自定义异常先定义协议里需要用的异常类型。这里要处理的核心是业务异常和系统异常要分开。系统异常如方法不存在、参数类型不对是代码问题应该返回标准错误码业务异常如用户不存在、订单状态不允许操作则应该走自定义错误码。class JsonRpcError(Exception): def __init__(self, code, message, dataNone): self.code code self.message message self.data data super().__init__(message) class ParseError(JsonRpcError): def __init__(self): super().__init__(-32700, Parse error) class InvalidRequest(JsonRpcError): def __init__(self): super().__init__(-32600, Invalid Request) class MethodNotFound(JsonRpcError): def __init__(self): super().__init__(-32601, Method not found) class InvalidParams(JsonRpcError): def __init__(self): super().__init__(-32602, Invalid params) class InternalError(JsonRpcError): def __init__(self, messageInternal error): super().__init__(-32603, message)把异常类拆分出来最大的价值在于路由分发时只要捕获JsonRpcError就能精确转成响应其他未知异常在兜底逻辑里转成通用的内部错误。这样客户端收到的错误对象永远是足够规范的。3.3 服务端路由与分发逻辑路由是核心中的核心。我维护一个字典把方法名映射到实际的 Python 函数。分发函数根据请求里的method去字典里查找找不到就抛MethodNotFound找到后把params解包传给目标函数。如果目标函数内部抛了业务异常它会自动冒泡到分发层被捕获并返回。class JsonRpcServer: def __init__(self): self._methods {} def register(self, nameNone): def decorator(func): self._methods[name or func.__name__] func return func return decorator def _invoke_single(self, request): if isinstance(request, list): return self._invoke_batch(request) if not isinstance(request, dict): raise InvalidRequest() if request.get(jsonrpc) ! 2.0: raise InvalidRequest() method request.get(method) if not isinstance(method, str) or method : raise InvalidRequest() params request.get(params, []) if not isinstance(params, (list, dict)): raise InvalidParams() func self._methods.get(method) if func is None: raise MethodNotFound() try: if isinstance(params, dict): result func(**params) else: result func(*params) except JsonRpcError: raise except Exception as e: # 记录日志后转为内部错误避免把堆栈细节暴露给客户端 raise InternalError(fServer internal error: {e}) if id in request and request[id] is not None: return {jsonrpc: 2.0, result: result, id: request[id]} return None def _invoke_batch(self, requests): if len(requests) 0: raise InvalidRequest() return [resp for resp in (self._invoke_single(req) for req in requests) if resp is not None] def handle(self, raw_body): try: data json.loads(raw_body) except json.JSONDecodeError: data None if data is None: return {jsonrpc: 2.0, error: ParseError().to_dict(), id: None} try: result self._invoke_single(data) if result is None: return None return result except JsonRpcError as e: return {jsonrpc: 2.0, error: e.to_dict(), id: data.get(id, None) if isinstance(data, dict) else None}这段代码里有两个容易忽略的细节。第一空的 batch 数组要抛InvalidRequest如果不处理客户端发了[]你回一个空数组就把协议语义弄歪了。第二notification 的返回是None但 HTTP 层依然要回 200 空 body不能因为业务层没有响应就断开连接。我在 HTTP 包装层会做区分如果handle返回None就响应 204。3.4 HTTP 层封装既然走的是 RPC over HTTP那么入口函数只需要做一件事把请求体传给JsonRpcServer.handle然后把结果以 JSON 响应。这里我固定用application/json作为 Content-Type。虽然 JSON-RPC 协议本身不限定传输层但在 HTTP 上很多框架默认的 POST 表单处理会干扰原始 body 的读取所以我都会在代码里显式指定request.get_data()拿原始字节流避免被中间层解析掉。from http.server import BaseHTTPRequestHandler, HTTPServer class RpcHttpHandler(BaseHTTPRequestHandler): server_version JsonRpcServer/1.0 def do_POST(self): content_length int(self.headers.get(Content-Length, 0)) raw self.rfile.read(content_length) response rpc_server.handle(raw) if response is None: self.send_response(204) self.end_headers() return body json.dumps(response, ensure_asciiFalse).encode(utf-8) self.send_response(200) self.send_header(Content-Type, application/json; charsetutf-8) self.send_header(Content-Length, str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, format, *args): # 减少调试噪音 pass如果不是自研而是引入现有框架整体结构也一样。Flask 里就是app.post(/rpc)一个路由FastAPI 里甚至可以用Request拿原生 body 再做分发。最核心的handle方法完全可以复用。3.5 客户端封装id 生成与超时控制客户端相对简单核心就三步构造请求、发送、解析响应。但我踩过不少坑这里分享几个容易出问题的地方。第一个坑是 id 生成策略。很多人直接用当前时间戳当 id如果同一毫秒内并发发多个请求id 就重复了响应回来容易错乱。我推荐用一个进程内自增计数器配合进程号做前缀比如100001、100002这样单调递增。虽然 JSON-RPC 不要求 id 单调但越排他越好排查问题。第二个坑是超时。发送 RPC 时如果不设置超时一旦网络波动客户端请求可能挂很久。我的习惯是区分连接超时和读超时连接 3 秒读超时按业务复杂度给 10 到 30 秒。对于长时间任务不要在客户端死等同步结果交给异步通知或任务查询接口更稳健。一个最小实现如下import json import urllib.request class JsonRpcClient: def __init__(self, endpoint, timeout10): self.endpoint endpoint self.timeout timeout self._id 0 def _next_id(self): self._id 1 return self._id def call(self, method, paramsNone, timeoutNone): payload { jsonrpc: 2.0, method: method, params: params, id: self._next_id(), } req urllib.request.Request( self.endpoint, datajson.dumps(payload).encode(utf-8), headers{Content-Type: application/json}, methodPOST, ) with urllib.request.urlopen(req, timeouttimeout or self.timeout) as resp: data json.loads(resp.read().decode(utf-8)) if error in data: raise JsonRpcError(data[error][code], data[error][message], data[error].get(data)) return data.get(result)用的时候一行调用就行client JsonRpcClient(http://127.0.0.1:8000/rpc) user client.call(user.getById, {userId: 1001})需要强调的还是要看error字段优先于result。我遇到过一些客户端实现先看 result 再看 error导致服务器返回 error 时居然把 error 对象当成结果返回。正确的检查顺序永远是先判断有没有 error有 error 就抛异常或者走错误分支。3.6 关于参数传递风格的最佳实践jsonRpc 的 params 既支持数组又支持对象。我自己的项目里新建接口一律推荐用对象传参。数组传参会带来一个严重问题调用方必须记得每个位置的含义一旦后续服务端参数顺序调整客户端旧版本传参就会错位而且不会产生任何编译期报错只能在运行时暴露。对象传参让每个参数都有名字比如{userId: 1001, includeProfile: true}。就算服务端以后增加了新参数旧客户端不传也不影响。配合服务端的默认值兼容性非常好。只有那种参数极少的接口才建议用数组比如一个ping不带任何参数或者add(1, 2)这种纯算数方法。4. 生产环境里的坑与排查技巧4.1 id 类型引起的诡异对不上这个问题的表现是服务端明明把 results 返回了客户端却认为响应和请求对不上。原因很直接id 用了「不同格式但在 JSON 里会被混淆」的值。比如一个客户端发字符串1服务端返回数字1虽然看着都是 1但类型不一致严格比较就会失败。解决办法是在客户端统一 id 类型服务端也统一不修改请求的 id。实现时服务端响应里的 id 必须原样从请求里复制不能做任何类型转换。我项目里的规范就是永远用整型自增 id杜绝字符串和整型混用。这样排查日志的时候也方便直接按 id 搜。4.2 批量请求里的部分失败批量请求最大的坑在于“一条失败要不要影响其他条”。协议本身对此没有强制规定有些实现是“有一条出错就整体返回错误”有些是“每条请求单独处理错误条目留在对应的响应位上”。实际开发中我建议按独立处理来设计每个请求单独执行单独返回 result 或 error。如果某一项出错不影响其他项执行。这更符合批量调用的直觉也方便客户端针对每一项分别判断。典型的批量响应长这样[ {jsonrpc: 2.0, result: 1, id: 1}, {jsonrpc: 2.0, error: {code: -32601, message: Method not found}, id: 2}, {jsonrpc: 2.0, result: 3, id: 3} ]但这里有个细节批量请求通常意味着多条业务操作可能不是并发安全的。如果同一批请求里既要查又要改同一条数据服务端实现时必须考虑事务边界。我就遇到过客户端发一个批量请求先减库存后查库存结果因为执行顺序问题查到了旧数据。所以凡是批量里有“写后读”依赖的我建议拆成两次独立调用或者服务端对批量请求加一个可选的串行化事务开关。4.3 服务端吞掉异常导致空响应写服务端时最常见的错误是最外层直接try-except捕获了所有异常然后 an empty 200 返回。客户端等半天拿到的却是空 body解码 JSON 时报错一时不知道是服务端崩了还是网络异常。排查思路也很简单首先确认服务端是否在 HTTP 层把异常转换成了-32603错误响应。如果发现返回了空 body优先查日志看看服务端是否在构造响应体之前就写入了 header。另一个常见原因是框架的异常中间件把异常直接吞掉在业务代码外边返回了一个默认的 HTTP 500。我习惯是在入口处包一层统一错误处理try: response rpc_server.handle(raw) except Exception: traceback.print_exc() response {jsonrpc: 2.0, error: InternalError().to_dict(), id: None}不管什么异常至少保证客户端能收到结构合法的 JSON-RPC 错误响应而不是一堆堆栈文本或者空 body。这对客户端排查问题有实质帮助能少一层猜测。4.4 超大 JSON 和深层嵌套的安全问题jsonRpc 虽然只用 JSON但 JSON 本身可能被构造得极其复杂比如嵌套 10000 层数组、超大字符串。如果服务端不做任何限制一个恶意请求或一个 bug 客户端就可能直接把服务端的内存和 CPU 打满。我的做法是在入口层加两个保护max_body_size和max_depth。比如 body 超过 1MB 直接拒绝重试也没必要JSON 解析后递归深度超过 100 层也直接返回InvalidRequest。Python 里解析 JSON 默认有递归深度限制但总会抛一个很底层的异常不如自己可控。此外方法执行前对关键参数做类型校验别让一个字符串被误当成列表迭代否则容易产生比较奇怪的异常。4.5 鉴权、日志与追踪的最小实践这些虽然不属于协议本身但生产环境离不开。我的最小实践是三层传输层鉴权HTTP 入口统一校验Authorizationheader比如内部服务之间用固定的 token校验失败直接返回 401。方法级鉴权某些方法只允许特定角色调用。配合方法名的点号前缀可以做一个简单的权限表比如admin.*只允许管理员调用。全链路日志记录每个请求的id、method、params摘要、耗时、返回状态。响应失败时把 error 对象完整记录。日志格式我习惯用 JSON 一行一条包含trace_id、method、params_hash、cost_ms、code这些字段。排查慢调用和错误时直接按trace_id过滤就能快速定位问题。这套东西虽然简单但能解决绝大多数“不知道哪个方法出错了”的诉求。4.6 常见错误速查表现象可能原因处理办法收到 -32700body 不是合法 JSON 或者被中间层转码确认 Content-Type用原始字节解析收到 -32600请求对象非 dict 或 jsonrpc 字段错误检查客户端封装是否少了 jsonrpc 字段收到 -32601method 名称写错或未注册核对服务端注册表检查前后缀收到 -32602params 类型不对或参数名不匹配检查是位置传参还是命名传参收到 -32001自定义业务错误如鉴权失败根据服务端约定的 data 做细分处理空 body / 连接断开服务端异常未走统一错误处理检查入口 try-except先保证错误响应响应 id 和请求 id 不一致服务端或客户端做了类型转换统一 id 类型并原样回传批量请求整体失败批量实现没有逐条独立处理改为逐条调用单条失败不影响其他5. 进一步扩展从单机到服务化jsonRpc 做单个服务很简单但一旦服务多了还是会遇到“怎么发现服务地址”“怎么做负载均衡”“服务挂了怎么切换”的问题。这里不展开讲服务网格只说低成本的做法可以在 jsonRpc 外面包一层代理服务客户端只连代理代理按 method 前缀把请求转发到不同的后端实例。这样的好处是客户端不需要每个服务都配一个地址。我之前做过一个类似的内部网关用一张静态路由表维护 method 前缀和后端地址的映射user.* - 10.0.0.11:8000/rpc order.* - 10.0.0.12:8000/rpc report.* - 10.0.0.13:8000/rpc代理剥掉传输层细节后把原始 jsonRpc body 原封不动转发给后端再把后端响应原样传回。这个方法本质上就是在协议层没有做任何改动只是多跳了一跳。如果后面服务更多了再引入注册中心做动态发现也不难路由表从静态配置变成“服务名 实例列表”转发时按轮询或加权策略选实例。这套思路在中小型团队里已经足够稳定比直接上全套微服务框架轻量太多。5.1 超时策略和熔断怎么落地当服务多了以后客户端“一刀切”式的超时就不够用了。我给不同方法配不同超时比如查询类 5 秒报表生成类 30 秒然后对失败率高的方法做熔断连续失败 N 次后直接快速失败不再请求后端过一会儿再放一部分流量试探。这个思想的落地点在于所有错误最终都统一聚合成 JsonRpcError所以熔断器只需要依赖 error code 就行比如只对 -32603 或网络错误计数而对业务类的 -32001 不计数因为它们不是服务端故障。5.2 和异步消息系统的配合不是所有调用都适合同步等待结果。比如用户上传了一批订单客户端希望服务端处理完再通知结果这时同步 RPC 会让调用方等太久。我的做法是把 jsonRpc 和消息队列配合起来入口方法收到请求后把任务投递到队列立刻返回一个taskId客户端稍后用另一个 jsonRpc 方法查询任务状态。这样既保留了 jsonRpc 的调用语义又避免了长时间占用连接。这个模式在文件处理、批量导入、异步报表的场景里特别实用。5.3 遇到性能瓶颈怎么优化jsonRpc 的性能瓶颈通常不在协议本身而在序列化和网络 IO。简单实测下来Python 用标准 json 库序列化一个小请求耗时大概在几十微秒到上百微秒级别HTTP 往返才是大头。如果压测发现吞吐不够我一般按顺序做这几件事开连接复用、合并批量请求、换更快的 JSON 库比如用 C 扩展实现的那几个、必要时再考虑上异步框架。记住一条原则先用最简单的方案跑通再根据压测数据决定要不要优化。很多项目一上来就用重度框架反而把问题复杂化了。最后再分享一点项目中的个人体会jsonRpc 这套东西我实际用了好几年最大的感受就是它把“服务间沟通”变成了一件自然且可控的事。要说它有什么魔力其实没有它就是一个极简的、能被任何语言解析的调用协议。但因为简单它的坑往往藏在实现细节里id 怎么回传、错误怎么区分、批量怎么处理、超时怎么兜底。这些细节决定了一次调用在真实环境里是不是足够稳。我踩过很多次 id 类型不一致的坑也看过服务端吞异常导致客户端等超时的现场所以特别想把这些经验记录下来。如果你现在正准备给内部系统设计 RPC或者被现有接口的调用方式绕得头疼不妨先拿 jsonRpc 搭一个最小原型让服务端的“函数”能真正被远程调用起来再逐步填充鉴权、日志、监控这些周边能力。它的上手速度绝对能让你意外而且一旦你熟悉了这套思路后续再接触 gRPC 这类更重的方案时心里也会更清楚“强约束”到底解决的是哪一部分问题。

相关新闻

寝室卫生管理系统毕设:数据库设计、状态流转与权限落地全解析

寝室卫生管理系统毕设:数据库设计、状态流转与权限落地全解析

简介:一份围绕“宿舍卫生管理系统的设计与实现”编写的本科毕业设计论文,适合软件工程、计算机等专业学生撰写毕业论文或做课程设计时参考。内容针对高校宿舍卫生人工记录费时费力、效率低的痛点,给出了面向管理员的信息化管理方案。文档涵盖…

2026/10/11 16:02:24 阅读更多 →
SQL注入报错注入实战:extractvalue与updatexml原理详解

SQL注入报错注入实战:extractvalue与updatexml原理详解

从报错信息里“抠”数据,这事其实挺讲究。很多新手刚开始搞安全测试,拿到一个疑似注入点,第一反应就是上手 union select ,结果发现页面没回显位、或者直接报错,一下子就卡住了。这时候,如果数据库的错误…

2026/10/11 16:02:24 阅读更多 →
VMP3.6虚拟机驱动兼容性开发指南:绕过检测的内核接口白名单

VMP3.6虚拟机驱动兼容性开发指南:绕过检测的内核接口白名单

简介:这是一份面向Windows内核驱动开发者与逆向安全研究者的VMware Workstation Pro 3.6反虚拟机检测驱动源码,专为绕过VMP 3.6版本的虚拟环境识别机制而设计,适用于恶意代码分析、沙箱逃逸研究、安全产品兼容性测试等高阶技术场景。资源包共…

2026/10/11 16:01:24 阅读更多 →

最新新闻

YOLO异物检测实战:从数据到部署,误报率压到千分之三

YOLO异物检测实战:从数据到部署,误报率压到千分之三

简介:这份资源是面向深度学习入门者、毕业设计或课程设计学生的YOLO异物检测完整项目包,聚焦工业制造场景下的实时目标检测与质量控制问题。压缩包共382个文件,约52MB,以120张jpg与72张png图像数据、112个pt模型权重、26个Python脚…

2026/10/11 16:44:51 阅读更多 →
互联网金融洗牌加剧,大数据风控成平台突围关键

互联网金融洗牌加剧,大数据风控成平台突围关键

互联网金融竞争白热化,风控能力决定平台能否在洗牌中胜出。以P2P网贷为例,大数据正渗透风控全流程。 销售环节,核心是验证客户意愿与信息真实性。信贷员模式强调“四亲见”:亲见申请人、证件、签字及单位。 审批环节,系…

2026/10/11 16:44:51 阅读更多 →
RabbitMQ消息不丢失:生产者确认机制原理与异步确认实践

RabbitMQ消息不丢失:生产者确认机制原理与异步确认实践

用 RabbitMQ 传业务消息,最怕的不是消息延迟,而是消息丢了你却不知道。我见过不少项目,刚开始接入的时候都是发完就算完事——不开启 Confirm,不处理回执,直到某次线上对账发现数据少了,顺着链路排查半天&a…

2026/10/11 16:44:51 阅读更多 →
视频孪生技术在交通领域的应用架构、典型案例与竞争格局

视频孪生技术在交通领域的应用架构、典型案例与竞争格局

视频孪生技术在交通领域的应用架构、典型案例与竞争格局视频孪生正在成为智慧交通从“可视化展示”迈向“空间智能决策”的重要技术路径。与传统数字孪生相比,视频孪生更强调以实时视频为感知入口,将二维监控画面、三维空间、物联网数据和业务系统统一到…

2026/10/11 16:44:51 阅读更多 →
Java爬虫工程化实战:从HttpClient到反爬与调度系统设计

Java爬虫工程化实战:从HttpClient到反爬与调度系统设计

做数据采集项目时,很多人第一反应是用 Python 写爬虫,但我们在实际落地一个多城市公共交通数据采集系统时,最终选型却定为 Java。Java 爬虫在并发控制、工程化整合和长期稳定性上确实有它不可替代的位置。这篇东西不是教程式的废话堆砌&#…

2026/10/11 16:43:51 阅读更多 →
ArtCraft 2026 路线图刷屏:从创作 IDE 到『开放的 OpenAI』,野心有多大

ArtCraft 2026 路线图刷屏:从创作 IDE 到『开放的 OpenAI』,野心有多大

ArtCraft 2026 路线图刷屏:从创作 IDE 到『开放的 OpenAI』,野心有多大 【免费下载链接】artcraft ArtCraft is an intentional crafting engine for artists, designers, and filmmakers 项目地址: https://gitcode.com/GitHub_Trending/ar/artcraft …

2026/10/11 16:43:51 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

2026/10/11 0:00:27 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →