grpc

package
v0.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2026 License: MIT Imports: 10 Imported by: 0

README

grpc proxy

一个 gRPC 透明代理实现:

  • 代理作为 gRPC server 接收入站请求
  • 代理作为 gRPC client 连接到目标 gRPC server 并转发请求

安装

go get github.com/fireflycore/go-proxy

快速开始

1) 透明代理(UnknownServiceHandler)

通过注入 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)
}

2) 使用固定目标连接(同一个 ClientConn)

如果所有请求都转发到同一个目标 gRPC server,可直接使用 NewProxy(内部已默认启用代理 codec 与 metadata 透传):

grpcBackendConn, _ := grpc.Dial("127.0.0.1:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
proxyServer := grpcProxy.NewProxy(grpcBackendConn)
_ = proxyServer

API 说明

  • StreamDirector:按 fullMethodName 选择目标连接(出站 client 侧),并可返回新的 outgoing context。
  • TransparentHandler:生成可用于 grpc.UnknownServiceHandler 的透明代理 handler。
  • RegisterService:按服务名/方法名注册白名单代理(仅暴露指定方法)。与 UnknownServiceHandler 的“透明兜底转发”不同,白名单模式下未注册的方法会返回 Unimplemented,适合需要严格控制暴露面的网关/跳板。
  • DefaultProxyServerOpt:代理 server 必需的 codec 配置(确保请求按原始 protobuf bytes 转发)。

RPC 模式支持

该代理以“统一的双向流”模型承载转发,但兼容 gRPC 的四种 RPC 模式:

  • 单-单(Unary):转发 1 条请求 + 1 条响应
  • 单-流(Server Streaming):转发 1 条请求 + N 条响应
  • 流-单(Client Streaming):转发 N 条请求 + 1 条响应
  • 流-流(Bidirectional Streaming):双向持续转发 N 条请求/响应

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BaseProtoCodec encoding.Codec = ProtoCodec{}

baseProtoCodec 提供标准 proto 编解码能力。 这里使用内部实现作为 fallback,避免 grpc-go 的 codec registry 未注册 "proto" 时返回 nil。

Functions

func DefaultClientCallOpts

func DefaultClientCallOpts() []grpc.CallOption

DefaultClientCallOpts 返回代理 client stream 的默认调用选项。 通过强制 codec,确保 client stream 使用与 server 侧一致的“原始 bytes”协议。

func DefaultProxyOpt

func DefaultProxyOpt(cc *grpc.ClientConn) grpc.ServerOption

DefaultProxyOpt 返回 UnknownServiceHandler 配置,使 server 能转发“未注册的服务/方法”。

func DefaultProxyServerOpt

func DefaultProxyServerOpt() grpc.ServerOption

DefaultProxyServerOpt 为代理 server 注入 codec。 该 codec 会把消息当作原始 bytes 透传,从而无需目标服务的具体消息类型。

func NewProxy

func NewProxy(dst *grpc.ClientConn, opts ...grpc.ServerOption) *grpc.Server

NewProxy 创建一个透明代理 Server,并默认启用: - 原始 protobuf bytes 转发 codec(server 侧) - UnknownServiceHandler 透明转发(代理作为 client 连接到目标 server)

func RegisterService

func RegisterService(server *grpc.Server, director StreamDirector, serviceName string, methodNames ...string)

RegisterService 注册代理服务

func TransparentHandler

func TransparentHandler(director StreamDirector) grpc.StreamHandler

TransparentHandler 提供一个透明代理的方式: - 代理作为 gRPC server 接收入站请求 - 代理作为 gRPC client 连接到目标 server 并转发请求 返回值可以作为 grpc.UnknownServiceHandler 使用

Types

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

func (*Handler) ForwardInboundToOutbound

func (h *Handler) ForwardInboundToOutbound(src grpc.ServerStream, dst grpc.ClientStream) chan error

func (*Handler) ForwardOutboundToInbound

func (h *Handler) ForwardOutboundToInbound(src grpc.ClientStream, dst grpc.ServerStream) chan error

func (*Handler) Handler

func (h *Handler) Handler(srv interface{}, serverStream grpc.ServerStream) error

Handler 是代理功能的核心所在,负责将请求转发到其他服务。 就像调用任何 gRPC 服务端流一样。 使用 RawProtoFrame 类型作为载体,在输入流和输出流之间转发调用。 srv 参数是为了满足 grpc.StreamHandler 接口签名要求,在代理场景下不使用。

type ProtoCodec

type ProtoCodec struct{}

ProtoCodec 是最小可用的 proto 编解码实现,仅用于 fallback。

func (ProtoCodec) Marshal

func (ProtoCodec) Marshal(v any) ([]byte, error)

func (ProtoCodec) Name

func (ProtoCodec) Name() string

func (ProtoCodec) Unmarshal

func (ProtoCodec) Unmarshal(data []byte, v any) error

type RawProtoCodec

type RawProtoCodec struct{}

RawProtoCodec 是代理 codec: - 若 v 是 *RawProtoFrame:直接透传 payload bytes - 否则:回退到 baseProtoCodec(标准 proto 编解码)

func (RawProtoCodec) Marshal

func (RawProtoCodec) Marshal(v any) ([]byte, error)

func (RawProtoCodec) Name

func (RawProtoCodec) Name() string

func (RawProtoCodec) Unmarshal

func (RawProtoCodec) Unmarshal(data []byte, v any) error

type RawProtoFrame

type RawProtoFrame struct {
	// payload 为一条 protobuf message 的原始序列化结果。
	Payload []byte
}

RawProtoFrame 是代理层的“消息容器”: - payload 保存原始 protobuf 消息 bytes - RawProtoFrame 会把 RecvMsg/SendMsg 的 v 识别为 *RawProtoFrame,并直接读写 payload

type StreamDirector

type StreamDirector func(ctx context.Context, fullMethodName string) (context.Context, *grpc.ClientConn, error)

func DefaultDirector

func DefaultDirector(cc *grpc.ClientConn) StreamDirector

DefaultDirector 返回一个固定目标连接的 director,并且会把 incoming metadata 复制到 outgoing context。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL