hyperf 微服务 rpc 调用失败主因是契约未对齐、协议混用或注册未生效;需统一 interface 包、严格命名空间、匹配传输协议(http/tcp 不可混)、启用服务治理与 consul 正确配置,并确保 json-rpc 2.0 响应格式合规。

Hyperf 微服务拆分后 RPC 调用失败,90% 是契约没对齐、协议配错或注册没生效,不是框架问题。
接口契约必须两端完全一致,连命名空间都不能差一个字符
Hyperf 的 JSON-RPC 不靠“猜”,而是靠 interface 文件在运行时做方法签名校验。消费者加载的 CalculatorServiceInterface 和提供者实现的必须是同一个类文件(含完整命名空间),否则会报 Call to undefined method ...::add()。
- 正确做法:把接口定义抽成独立 Composer 包(如
common),Provider 和 Consumer 都通过composer require your-org/common引入,而非各自 copy-paste - 命名空间要严格一致:
AppJsonRpcCalculatorServiceInterface在两边的composer.json中都得能被自动加载器识别,检查autoload psr-4是否包含"App\JsonRpc\": "app/JsonRpc/" - 返回类型不能省略:
int和int|null在Normalizer层处理逻辑不同,反序列化时直接失败
jsonrpc-http 和 jsonrpc-tcp 绝对不能混用
它们底层 Transporter 和 Packer 完全不兼容:jsonrpc-http 走 HyperfHttpClient 发 HTTP 请求,jsonrpc-tcp 用 SwooleCoroutineClient 直连 TCP 端口。混配会导致连接拒绝、卡住或返回 HTML 错误页。
- Provider 配了
'name' => 'jsonrpc-tcp'(监听 9503),Consumer 却配'protocol' => 'jsonrpc-http'→ 报错Connection refused或返回 Nginx 欢迎页 - Provider 配
jsonrpc-http(监听 9504),Consumer 配jsonrpc-tcp→ 报错Invalid response,因为 HTTP Server 无法解析 TCP 流中的 EOF 帧 - 调试建议:用
curl -v http://127.0.0.1:9504测 HTTP,用tcpdump -i lo port 9503 -A抓 TCP 流,确认实际走的是哪条路
服务注册到 Consul 后 Consumer 还找不到节点?检查这四点
报 No service found 不是网络不通,是治理层没拉到元数据。Hyperf 的服务发现是运行时行为,依赖 governance 组件主动轮询。
-
config/autoload/services.php中'enable' => ['register' => true, 'discovery' => true]必须同时开启,缺一不可 -
@RpcService(publishTo="consul")注解必须加在实现类上,只写@RpcService默认只本地生效 -
config/autoload/consul.php的'host'不能写localhost—— Docker 容器里localhost指自己,要填 Consul 容器名(如consul-server)或宿主机 IP - Consul UI(
http://consul-server:8500)里查服务列表,确认服务名、Tag、健康状态是否正常;如果状态是critical,检查 Provider 是否启用了心跳检测
Consumer 调用时抛出 Invalid response,大概率是 Normalizer 或 ID 生成器出问题
ServiceClient->__request() 收到响应后会先过 Normalizer 反序列化,再比对 id 字段。这两步任一失败都会中断流程。
- 确保
config/autoload/normalizer.php已启用,且HyperfRpcClientNormalizerDefaultNormalizer能正确处理int/string类型字段 - 如果自定义了
IdGeneratorInterface,注意$id必须是字符串,不能是 int;否则checkRequestIdAndTryAgain()会因类型不匹配跳过校验 - Provider 返回的 JSON 必须符合 JSON-RPC 2.0 格式:
{"jsonrpc":"2.0","result":...,"id":...},少字段或多字段都会触发Invalid response
最常被忽略的是:服务提供者启动后,必须等 Consul 健康检查通过(默认 30 秒),Consumer 才能从治理中心拿到可用节点。别在 Provider 刚 start 就立刻 curl Consumer 接口,它真还没“上线”。











