Golang设计模式之简单拦截器模式 Go语言RPC调用中的横切关注点

0次阅读

Golang 设计模式之简单拦截器模式 Go 语言 RPC 调用中的横切关注点

Go RPC 中怎么给所有方法加统一日志或鉴权?

net/rpc 自带的 Server.RegisterName 无法直接插拦截逻辑,必须在服务端方法内部手动加——但这样重复写、难维护。真正可行的方式是包装 rpc.ServerServeCodec 或改用 http.ServeHTTP 做一层代理,不过最轻量且可控的做法是:在注册前,把原始服务对象用结构体嵌套 + 方法重写的方式“装饰”一遍。

  • 不要试图修改 rpc.Server 源码或反射劫持方法表——Go 的 reflect.Value.Call 在 RPC 方法签名不匹配时会 panic,且无法获取上下文参数
  • 推荐用匿名字段嵌入原服务,再为每个导出方法提供同名包装器,例如:func (s *loggedService) Add(r *Request, t *int) error {log.Printf("call Add"); return s.Service.Add(r, t) }
  • 注意:RPC 方法签名必须严格符合 func(*T1, *T2) error,包装器里不能漏掉指针类型或改返回值顺序,否则注册时静默失败

为什么不用中间件函数封装 rpc.ServeConn?

因为 rpc.ServeConn 是底层连接级处理,它只负责解包请求、调用对应方法、回写响应,不暴露“方法名”和“参数内容”——你没法在它之前判断该不该鉴权、记哪条日志。等你拿到的是已解析好的 *rpc.Requestcodec.ServerCodec,此时方法早已执行完毕或正在执行中。

  • rpc.ServeConn 的输入是 io.ReadWriteCloser,你最多能读到原始字节流,但 Go RPC 默认用 gob 编码,没有 schema 就无法安全反序列化请求头
  • 若强行在 ServeConn 外套一层 net.Conn 包装器(如 connWrapper),只能做连接层审计(比如 IP 限流),对业务方法无感知
  • 真正需要横切的场景(如按 method 名做黑白名单),必须落到服务端方法调用前一刻,也就是“服务对象方法被反射调用”的那个切面

简单拦截器模式在 gRPC 里还适用吗?

不适用。gRPC 原生支持 UnaryInterceptorStreamInterceptor,接口清晰、上下文透传完整,根本不需要手写装饰器。但如果你正从 net/rpc 迁移到 gRPC,别想着复用旧拦截逻辑——gRPC 的拦截器接收 context.Contextinterface{} 参数,而 net/rpc 完全没有 context,参数是硬编码的两个指针。

  • gRPC 拦截器里能拿到完整 method 字符串(如 /helloworld.Greeter/SayHello),net/rpc 只有结构体内方法名(如 Add),二者元信息粒度不同
  • 别试图用 gob 解码 net/rpc 请求体去模拟 gRPC 拦截——编码格式不公开、无文档、版本敏感,容易在 Go 升级后突然失效
  • 如果项目已重度依赖 net/rpc 又急需拦截能力,优先考虑升级到 gRPC,而不是给老代码打补丁

最容易被忽略的坑:RPC 方法的 receiver 类型影响拦截器生效

Go 的 net/rpc 要求注册的服务对象必须是导出类型,且方法 receiver 必须是 ** 指针或值类型一致 **。如果你用结构体嵌套实现拦截器,但原始服务是以值类型定义 receiver(如 func (s Service) Add(……)),而拦截器用指针嵌入(type loggedService struct{*Service}),那么 loggedService 就不会继承那些值 receiver 方法——RPC 注册时会跳过它们,不报错,但调用直接返回 method not found

立即学习 go 语言免费学习笔记(深入)”;

  • 检查原始服务方法的 receiver:运行 go doc yourpkg.Service,看方法列表前缀是 (Service) 还是 (*Service)
  • 拦截器结构体的嵌入字段类型必须完全匹配,*Service 就嵌 *ServiceService 就嵌 Service,混用必丢方法
  • RPC 不支持 interface{} 注册,所以别想用 interface{Add(……) } 抽象一层再装饰——注册时会 panic:”service has no exported methods
事情说清了就结束。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-12发表,共计1741字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources