go的net/rpc默认不支持跨语言调用,因其使用go专属gob编码,python/java等语言无法解析,直接通信会报invalid gob magic number或unexpected eof;需改用jsonrpc或grpc。

Go 的 net/rpc 本身不支持跨语言调用,且默认基于 Gob 编码,HTTP 传输仅是可选封装;直接用于生产环境前必须替换序列化方式或改用 gRPC。
为什么 net/rpc 默认不能和 Python/Java 通信
Go 标准库的 net/rpc 默认使用 gob 编码,这是 Go 特有的二进制格式,其他语言没有原生支持。即使你用 http.ServeMux 暴露服务,客户端仍需用 gob 解码,否则会遇到类似 unexpected EOF 或 malformed Gob data 错误。
常见误操作:
- 用
curl直接请求 RPC HTTP 端点,期望返回 JSON —— 实际返回的是二进制 gob 流,肉眼不可读 - 在 Python 客户端用
requests.post发送 JSON body —— 服务端gob.Decoder会立即报错
如何让 net/rpc 支持 JSON-RPC(有限跨语言)
Go 提供了 net/rpc/jsonrpc 包,它把 RPC 方法调用封装成 JSON 格式,但注意:它仍是 Go 的 RPC 协议语义(比如要求方法名首字母大写、参数必须是两个结构体指针),不是通用 JSON-RPC 2.0 规范。
服务端启用 JSON-RPC 需手动注册连接,不能复用 http.DefaultServeMux 的自动路由:
listener, _ := net.Listen("tcp", ":8080")
server := rpc.NewServer()
server.RegisterName("Arith", new(Arith))
for {
conn, _ := listener.Accept()
// 关键:用 jsonrpc.ServeConn 而非 server.ServeCodec
go jsonrpc.ServeConn(conn)
}
客户端也必须用 jsonrpc.Dial:
client, _ := jsonrpc.Dial("tcp", "127.0.0.1:8080")
var reply int
err := client.Call("Arith.Multiply", &args, &reply)
注意事项:
- JSON-RPC 连接是一次性的,
Dial后必须显式Close,不支持长连接复用 - 错误信息以 JSON 形式返回,但结构固定:
{"error":"..."},无法自定义字段 - 不支持命名参数、可选参数、通知(notification)等 JSON-RPC 2.0 特性
为什么 rpc.Register 失败或方法不可见
Go RPC 对暴露的方法有严格签名约束,任何不满足都会导致调用时返回 method not found 或静默失败。
必须同时满足以下全部条件:
- 方法名首字母大写(即 exported)
- 接收者是指针类型(如
func (t *Arith) Multiply(...)) - 恰好有三个参数:接收者、请求结构体指针、响应结构体指针
- 第三个参数必须是指针(哪怕你想返回基本类型,也要包一层结构体)
- 所有参数结构体字段名首字母大写(否则
gob无法序列化)
典型反例:
// ❌ 字段小写 → gob 编码为空
type Args struct { A, B int }
// ✅ 必须大写
type Args struct { A, B int }
// ❌ 第三个参数不是指针
func (*Arith) Multiply(args Args, reply int) error
// ✅ 正确写法
func (*Arith) Multiply(args *Args, reply *int) error
替代方案:什么时候该放弃 net/rpc
如果你需要以下任一能力,net/rpc 就不该出现在技术选型里:
- 客户端用 JavaScript 调用(浏览器不支持 TCP 连接,而
net/rpc的 HTTP 模式只是 transport,不是 REST) - 需要流式响应(如日志 tail、实时推送)
- 要集成 OpenAPI 文档、OAuth2、限流、链路追踪
- 服务要被 Kubernetes Ingress 或 Nginx 路由(
net/rpc不遵循 HTTP 方法/路径语义)
更现实的选择是:gRPC-Go(强契约、多语言、HTTP/2)、或轻量级 REST + encoding/json(用 net/http 自建,可控性强)。标准库的 net/rpc 本质是教学示例级工具,它的设计目标从来不是工程落地。











