在 go 的 `jsonrpc` + `websocket` 组合中,标准 rpc 方法无法直接访问底层 `*websocket.conn`。本文介绍一种基于 `context.context` 和自定义 `servercodec` 的安全、可扩展方案,使 rpc 处理函数能获取连接元数据(如远程地址、header 等)。
Go 标准库的 net/rpc/jsonrpc 是面向无状态通信设计的,其 ServeConn 接口将 *websocket.Conn 封装后完全隔离,导致 RPC 方法(如 Multiply)无法感知调用来源。强行打破这一抽象虽可行,但会牺牲可维护性与兼容性。推荐采用 上下文注入(Context Injection) 方式,在不修改 RPC 协议语义的前提下,安全传递连接信息。
✅ 核心思路:通过自定义 ServerCodec 注入 context.Context
我们需实现一个符合 rpc.ServerCodec 接口的编码器,在反序列化请求参数时,自动将携带连接信息的 context.Context 注入到参数结构体的 Context 字段中。
1. 定义支持上下文的参数结构体
import (
"context"
"net/http"
"net/rpc"
"net/rpc/jsonrpc"
"reflect"
"sync"
)
type Args struct {
A int
B int
Context context.Context // 新增字段,用于接收注入的上下文
}
2. 实现自定义 ServerCodec
以下是一个轻量级 WebSocketContextCodec,它包装原始 jsonrpc.ServerCodec,并在 ReadRequestBody 阶段注入 context.WithValue: