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