Go的net/rpc不是“调用即连通”的黑盒,它对类型导出、服务注册、HTTP路径和gob编码有硬性约束:结构体及字段必须首字母大写,方法签名须为func(Args,Reply)error,服务端注册名与客户端调用名(如"Calc.Add")须完全一致,HTTP模式下路径必须严格匹配"/rpc"且客户端需用完整URL dial。

Go 的 net/rpc 不是“调用即连通”的黑盒,它对类型、注册、传输路径和编码格式有硬性约束;直接照抄示例代码大概率失败,核心问题几乎都出在结构体字段未导出、服务名不匹配或 HTTP 路径错位上。
结构体字段必须全部导出(首字母大写)
gob 编码只序列化导出字段,哪怕只漏一个字段小写,客户端传参就会被截断,服务端收到空值,还可能报 gob: type not found 或静默失败。
-
Args和Reply必须是导出结构体,字段名首字母大写:如type Args struct { A, B int },不能写成a, b int - 别用
interface{}做参数或返回值,gob 无法处理未注册的接口类型,错误信息常为rpc: gob error: type not registered for interface - 时间类型可用
time.Time(gob 内置支持),但自定义 time wrapper 类型需手动注册gob.Register
服务注册与方法签名必须严格匹配
服务端注册名、方法名、参数类型三者必须和客户端 Call 中的字符串完全一致,大小写、空格、点号都不能错。
- 注册时用
rpc.RegisterName("Calc", &server),调用时就得写"Calc.Add",不是"calc.Add"也不是"Calc.Add " - 方法签名只能是
func(*Args, *Reply) error形式:两个参数都必须是指针,返回值必须是error,接收者类型也得导出(如type Calc struct{},不能是calc struct{}) - 别把方法写成
func Add(...)(包级函数),必须绑定到导出类型上,且方法名首字母大写
HTTP 模式下路径和 client 初始化极易出错
HTTP-RPC 不是 REST API,它只响应 POST 到固定路径的 gob 编码请求,浏览器访问会 405,curl 手动发请求也基本失败。
立即学习“go语言免费学习笔记(深入)”;
- 服务端必须显式注册 handler:
http.Handle("/rpc", rpc.DefaultServer),路径不能是/api/rpc或/v1/rpc,否则客户端rpc.DialHTTP会 404 -
rpc.DialHTTP第二个参数必须是完整 URL(含协议、host、端口、路径),如"http://localhost:8080/rpc";写成"localhost:8080/rpc"会被当 host 解析,连到错误地址 - Go 1.22+ 已弃用
rpc.NewHTTPClient(),客户端应直接用rpc.DialHTTP("tcp", url),且确保http.Handle在http.ListenAndServe之前执行,否则首次调用可能因 handler 未就绪而超时
跨语言调用根本不可行,别试
net/rpc 默认用 gob 编码,其他语言没有标准 gob 解码器,协议层面就不通。所谓“配置 JSON-RPC”需要自己实现 rpc.ServerCodec,标准库不提供 rpc.DialJSON 这类快捷方式。
- 想对接 Python/JS/Java?直接换 gRPC 或 HTTP+JSON 接口,别在
net/rpc上改编码 - 哪怕只用 Go,也别依赖 gob 的隐式类型匹配——服务端和客户端的结构体必须来自同一份代码(或至少包路径、字段顺序、名称完全一致),否则
gob: type mismatch会在运行时爆发 - 生产环境建议加连接超时和调用超时,
rpc.DialHTTP不支持原生 timeout,得包装http.Transport或用带 context 的第三方封装
最麻烦的从来不是写几行注册和调用代码,而是两端结构体定义同步、路径字符串对齐、以及意识到 gob 编码带来的强耦合——它不像 JSON 那样容错,错一个字母、少一个星号,就静默失败或 panic。


















