Golang Gin框架搭配Grpc框架使用(监听同一端口)

Golang Gin框架搭配Grpc框架使用(监听同一端口)

方式一、该方式仅限给Gin配置了SSL证书、

http标准库会为配置了证书的http服务自动选用http/2协议,grpc建立在http/2协议上,所以没有配置SSL证书时请勿使用该方式

package main

// 入口
func main() {
	// 初始化grpc服务
	grpcServer := grpc.NewServer()
 
    /***** 注册你的grpc服务 *****/
 
    // 初始化一个空Gin路由
	router := gin.New()
 
	// 全局拦截
	router.Use(func(ctx *gin.Context) {
		// 判断协议是否为http/2
		// 判断是否是grpc
		if ctx.Request.ProtoMajor == 2 && 
                strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/grpc") {
			// 按grpc方式来请求
                        ctx.Status(http.StatusOK)  // 我本地测试这里不加状态码,客户端GRPC收到的是404状态码
			grpcServer.ServeHTTP(ctx.Writer, ctx.Request)
			// 不要再往下请求了,防止继续链式调用拦截器
			ctx.Abort()
			return
		}
		// 当作普通api
		ctx.Next()
	})
 
	/***** 添加你的api路由吧 *****/
 
	// 启动
	router.RunTLS(
		"0.0.0.0:8080",
		"你的SSL证书路径",
		"你的SSL私钥路径",
	)
}

方式二、当你不需要使用SSL证书或SSL证书配置在Nginx等服务上时,请使用该方式

package main
 
// 入口
func main() {
	// 初始化grpc服务
	grpcServer := grpc.NewServer()
 
    /***** 注册你的grpc服务 *****/
 
    // 初始化一个空Gin路由
	router := gin.New()
 
	// 全局拦截
	router.Use(func(ctx *gin.Context) {
		// 判断协议是否为http/2
		// 判断是否是grpc
		if ctx.Request.ProtoMajor == 2 && 
            strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/grpc") {
			// 按grpc方式来请求
			grpcServer.ServeHTTP(ctx.Writer, ctx.Request)
			// 不要再往下请求了,防止继续链式调用拦截器
			ctx.Abort()
			return
		}
		// 当作普通api
		ctx.Next()
	})
 
	/***** 添加你的api路由吧 *****/
 
	// 为http/2配置参数
	h2Handle := h2c.NewHandler(router, &http2.Server{}) // 禁用TLS加密协议
	// 配置http服务
	server := &http.Server{
        Addr: ":8080", 
        Handler: h2Handle,
    }
	// 启动http服务
	server.ListenAndServe()
}

增加http gateway

// server.go
package main

import (
	"fmt"
	pb "gohttp/proto/hello_http"
	"net/http"
	_ "net/http/pprof"
	"os"
	"strings"
	"time"

	"github.com/gin-contrib/pprof"
	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"golang.org/x/net/context"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"

	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/grpclog"
)

func main() {
	os.Setenv("HOST_PORT_0", "12000")
	grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stdout, os.Stdout, os.Stdout))
	var r = gin.Default()
	grpcServer := grpc.NewServer()
	pb.RegisterHelloHTTPServer(grpcServer, HelloHTTPService)

	r.Use(func(ctx *gin.Context) {
		// 判断协议是否为http/2
		// 判断是否是grpc
		if ctx.Request.ProtoMajor == 2 &&
			strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/grpc") {
			// 按grpc方式来请求
			ctx.Status(http.StatusOK)
			grpcServer.ServeHTTP(ctx.Writer, ctx.Request)
			// 不要再往下请求了,防止继续链式调用拦截器
			ctx.Abort()
			return
		}
		// 当作普通api
		ctx.Next()
	})
	gwmux := runtime.NewServeMux()
	ctx := context.Background()
	endpoint := "127.0.0.1:" + os.Getenv("HOST_PORT_0")
	// tslConfig := &tls.Config{}
	// creds := credentials.NewTLS(tslConfig)

	dopts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}

	if err := pb.RegisterHelloHTTPHandlerFromEndpoint(ctx, gwmux, endpoint, dopts); err != nil {
		grpclog.Fatalf("Failed to register gw server: %v\n", err)
	}
	r.Any("/example/echo", func(c *gin.Context) {
		gwmux.ServeHTTP(c.Writer, c.Request)
	})
	h2Handle := h2c.NewHandler(r.Handler(), &http2.Server{})
	server := &http.Server{
		Addr:    "0.0.0.0:" + os.Getenv("HOST_PORT_0"),
		Handler: h2Handle,
	}
	// 启动http服务
	server.ListenAndServe()
}
// 定义helloHTTPService并实现约定的接口
type helloHTTPService struct{}

// HelloHTTPService Hello HTTP服务
var HelloHTTPService = helloHTTPService{}

// SayHello 实现Hello服务接口
func (h helloHTTPService) SayHello(ctx context.Context, in *pb.HelloHTTPRequest) (*pb.HelloHTTPResponse, error) {
	grpclog.Infoln("收到请求grpclog")
	resp := new(pb.HelloHTTPResponse)
	resp.Message = "Hello " + in.Name + "."
	return resp, nil
}

// client.go
package main

import (
	pb "gohttp/proto/hello_http" // 引入proto包
	"os"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/grpclog"
)

func main() {
	var Address = os.Args[1]
	grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stdout, os.Stdout, os.Stdout))

	// 连接
	conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		grpclog.Fatalln(err)
	}
	defer conn.Close()

	// 初始化客户端
	c := pb.NewHelloHTTPClient(conn)

	// 调用方法
	req := &pb.HelloHTTPRequest{Name: "gRPC"}
	res, err := c.SayHello(context.Background(), req)

	if err != nil {
		grpclog.Fatalln(err)
	}

	grpclog.Println(res.Message)
}

// hello_http.proto
syntax = "proto3";

package hello_http;

option go_package = "./hello_http";

import "google/api/annotations.proto";


// 定义Hello服务
service HelloHTTP {
    // 定义SayHello方法
    rpc SayHello(HelloHTTPRequest) returns (HelloHTTPResponse) {
        // http option
        option (google.api.http) = {
            post: "/example/echo"
            body: "*"
        };
    }
}

// HelloRequest 请求结构
message HelloHTTPRequest {
    string name = 1;
}

// HelloResponse 响应结构
message HelloHTTPResponse {
    string message = 1;
}
curl -X POST -k http://192.168.9.2:12000/example/echo -d '{"name": "gRPC-HTTP is working!"}'
{"message":"Hello gRPC-HTTP is working!."}

 ./nocgoclient  192.168.9.2:12000
……
2022/05/31 18:50:41 INFO: Hello gRPC.
……

参考链接: https://blog.csdn.net/weixin_45985984/article/details/124071909

posted @ 2022-05-31 17:58  董大轩  阅读(4442)  评论(0编辑  收藏  举报