一个 gRPC 透明代理实现:
- 代理作为 gRPC server 接收入站请求
- 代理作为 gRPC client 连接到目标 gRPC server 并转发请求
go get github.com/fireflycore/go-proxy通过注入 Director 决定每个 RPC 的目标连接(出站 client 侧),并透传 metadata:
package main
import (
"context"
"net"
grpcProxy "github.com/fireflycore/go-proxy/grpc"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
func main() {
director := func(ctx context.Context, fullMethodName string) (context.Context, *grpc.ClientConn, error) {
endPoint := map[string][]string{
"/acme.demo.v1.DemoService/GetDemo": {"127.0.0.1:9000"},
}
nodes, ok := endPoint[fullMethodName]
if !ok || len(nodes) == 0 {
return ctx, nil, status.Errorf(codes.Unimplemented, "unknown method: %s", fullMethodName)
}
md, _ := metadata.FromIncomingContext(ctx)
outgoingCtx := metadata.NewOutgoingContext(ctx, md.Copy())
cc, err := grpc.DialContext(
outgoingCtx,
nodes[0],
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return outgoingCtx, nil, err
}
return outgoingCtx, cc, nil
}
lis, _ := net.Listen("tcp", ":8080")
server := grpc.NewServer(
grpcProxy.DefaultProxyServerOpt(),
grpc.UnknownServiceHandler(grpcProxy.TransparentHandler(director)),
)
_ = server.Serve(lis)
}如果所有请求都转发到同一个目标 gRPC server,可直接使用 NewProxy(内部已默认启用代理 codec 与 metadata 透传):
grpcBackendConn, _ := grpc.Dial("127.0.0.1:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
proxyServer := grpcProxy.NewProxy(grpcBackendConn)
_ = proxyServerStreamDirector:按fullMethodName选择目标连接(出站 client 侧),并可返回新的 outgoing context。TransparentHandler:生成可用于grpc.UnknownServiceHandler的透明代理 handler。RegisterService:按服务名/方法名注册白名单代理(仅暴露指定方法)。与 UnknownServiceHandler 的“透明兜底转发”不同,白名单模式下未注册的方法会返回Unimplemented,适合需要严格控制暴露面的网关/跳板。DefaultProxyServerOpt:代理 server 必需的 codec 配置(确保请求按原始 protobuf bytes 转发)。
该代理以“统一的双向流”模型承载转发,但兼容 gRPC 的四种 RPC 模式:
- 单-单(Unary):转发 1 条请求 + 1 条响应
- 单-流(Server Streaming):转发 1 条请求 + N 条响应
- 流-单(Client Streaming):转发 N 条请求 + 1 条响应
- 流-流(Bidirectional Streaming):双向持续转发 N 条请求/响应