http2、grpc 的反向代理的实现

20 篇文章 11 订阅

grpc、http2 反向代理的实现

代码地址 https://github.com/wanmei002/testgrpc-proxy

采用golang 的自带的代理 httputil.ReverseProxy

transport 采用 golang.org/x/net/http2 的http2.Transport

grpc 使用的是 http2, 如果要代理 grpc 请求,就需要开启 tls, tls 的生成请参考我以前的博客地址

服务端代码

func StartServer() {
	ca, err := private_key.NewCA("expvent.com")
	if err != nil {
		log.Fatal(err)
	}
	// 生成证书
	cliCert, err := tls.X509KeyPair(ca.CertPem(), ca.KeyPerm())
	if err != nil {
		log.Fatal(err)
	}
	cfg := &tls.Config{
		Certificates: []tls.Certificate{cliCert},
		ClientAuth:   tls.NoClientCert,
	}
	svc := grpc.NewServer(
		grpc.Creds(credentials.NewTLS(cfg)),// 使用证书
	)
	billings.RegisterBillingServiceServer(svc, &Service{})
	reflection.Register(svc)
	ls, err := net.Listen("tcp", ":8089")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	fmt.Println("start port 8089")
	err = svc.Serve(ls)
	if err != nil {
		fmt.Printf("failed to serve: %v", err)
	}
	return
}

客户端请求代码

func clientReq() {
	time.Sleep(4 * time.Second)
	opt := grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		fmt.Printf("method:%s; req:%v; reply:%v\n", method, req, reply)
		method = fmt.Sprintf("%s%s", "/r/apps/test-grpc", method) // 模拟修改路由
		fmt.Println("method after: ", method)
		err := invoker(ctx, method, req, reply, cc, opts...)
		return err
	})
	ctx := context.Background()
	// 模拟添加 token
	ctx = metadata.NewOutgoingContext(ctx, metadata.New(map[string]string{
		"Authorization": "Bearer aaaa.bbb.ccc",
	}))
	// 连接代理服务
	conn, err := grpc.DialContext(context.Background(), "127.0.0.1:9001", grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})), opt)
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := billings.NewBillingServiceClient(conn)

	resp, err := client.GetAppBilling(ctx, &emptypb.Empty{})
	if err != nil {
		fmt.Printf("could not greet: %v\n", err)
		return
	}
	log.Println(resp.Resp)
}

反向代理代码

func main() {
    svc := &http.Server{
        Addr:    ":9001",
        Handler: getHandler(),
    }
    ca, err := private_key.NewCA("expvent.com")
    if err != nil {
        log.Fatal(err)
    }
    cliCert, err := tls.X509KeyPair(ca.CertPem(), ca.KeyPerm())
    if err != nil {
        log.Fatal(err)
    }
    svc.TLSConfig = &tls.Config{
        Certificates: []tls.Certificate{cliCert},
    }
    err = svc.ListenAndServeTLS("", "")
    //err = svc.ListenAndServe()
    if err != nil {
        panic(err)
    }
}

func getHandler() http.Handler {
    proxy := &httputil.ReverseProxy{}
    proxy.Director = func(req *http.Request) {
        // 必需是 https
        req.URL.Scheme = "https"
        // 跳转到二级反向代理
        req.URL.Host = "127.0.0.1:9002"
        // 去除前缀
        req.URL.Path = strings.TrimPrefix(req.URL.Path, "/r/apps/test-grpc")
        req.RequestURI = strings.TrimPrefix(req.RequestURI, "/r/apps/test-grpc")
        req.Host = "127.0.0.1:9002"
    }
    proxy.Transport = &http2.Transport{
        AllowHTTP:       true,
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    return proxy
}

问题: error reading server preface: http2: frame too large

看看使用的是不是 http2.Transport, 还有是不是启用的是 https 服务

http2 只支持 https scheme

要使用 C++ 实现 HTTP 接口,可以使用 gRPC 的 HTTP/1.1 网关。gRPC 的 HTTP/1.1 网关是一个 gRPC 服务器,它将 RESTful HTTP API 转换为 gRPC。这个网关可以用于将现有的 RESTful HTTP API 转换为 gRPC,或者让 gRPC 服务提供 RESTful HTTP API。 以下是实现过程的一些步骤: 1. 安装和设置 gRPC:在 C++ 中使用 gRPC,需要安装 gRPC 和 Protocol Buffers。可以从 gRPC 官方网站下载和安装 gRPC。 2. 定义 proto 文件:定义包含 HTTP 端点和请求/响应消息的 proto 文件。可以使用 protobuf 编译器将 proto 文件编译成 C++ 代码。 3. 实现 gRPC 服务:实现 gRPC 服务并编写处理程序来处理 HTTP 端点。 4. 配置 HTTP/1.1 网关:配置 HTTP/1.1 网关,使其将 RESTful HTTP API 转换为 gRPC。 5. 启动 HTTP/1.1 网关:启动 HTTP/1.1 网关,并且可以使用 RESTful HTTP API 访问 gRPC 服务。 在实现过程中,需要注意以下几点: 1. 在定义 proto 文件时,需要使用 HTTP 规范定义请求/响应消息。 2. 在实现 gRPC 服务时,需要根据 HTTP 规范处理 HTTP 请求和响应。 3. 在配置 HTTP/1.1 网关时,可以使用 Envoy 或 Istio 这样的开源代理来进行配置。 4. 在启动 HTTP/1.1 网关时,需要将其绑定到正确的端口,以便可以使用 RESTful HTTP API 访问 gRPC 服务。 总体来说,使用 gRPC 的 HTTP/1.1 网关可以在 C++ 中实现 HTTP 接口,同时也可以让 gRPC 服务提供 RESTful HTTP API。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值