Go微服务六 Go – gRPC – TLS 使用rpc-gatway 不同端口同时提供rpc和http服务 客户端rpc和http选其一调用

16,744 次浏览次阅读
没有评论

为什么要这么做:

不管时内部另外一个服务还是外部第三方服务,如果调用者也使用了 rpc,可以调用写好的服务端。

如果调用者没有使用 rpc 而使用了 http RESTFUL API,那就要使用 rpc-gatway 提供 http 服务了

简而言之:一个商品详情服务接口即可以提供 rpc 也可以支持 http RESUTFUL API (rpc 和 api 不同的启动端口)

一 安装

go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
go get google.golang.org/grpc/cmd/protoc-gen-go-grpc

二 COPY

拷贝 google 到服务端项目目录下的 pbfiles 中

三 修改.proto 文件

syntax = "proto3";

package services;

import "google/api/annotations.proto"; 

option go_package = "../services";

message ProdRequest {int32 prod_id = 1;}

message ProdResponse {int32 prod_stock = 1;}

service ProdService {rpc GetProdStock (ProdRequest) returns (ProdResponse) {option (google.api.http) = {get: "/v1/prod/{prod_id}"
    };
  }
}

执行以下命令:

protoc --go_out=plugins=grpc:../services Prod.proto 
protoc --grpc-gateway_out=logtostderr=true:../services Prod.proto  # 生成一个 xxx.pb.gw.go 文件 

四 将客户端项目下的 client.key 和 client.crt 复制到本项目的 keys 目录下

五 封装服务端和客户端证书配置

helper/CertHelper.go

package helper

import (
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "log"

    "google.golang.org/grpc/credentials"
)

//GetServerCred 获取服务端证书配置
func GetServerCred() credentials.TransportCredentials {
    // 公钥中读取解析公钥、私钥
    cert, err := tls.LoadX509KeyPair("keys/server.crt", "keys/server.key")
    if err != nil {log.Fatal("LoadX509KeyPair error", err)
    }
    // 创建证书池
    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("keys/ca.crt")
    if err != nil {log.Fatal("read ca pem error ", err)
    }

    // 解析证书
    if ok := certPool.AppendCertsFromPEM(ca); !ok {log.Fatal("AppendCertsFromPEM error ")
    }

    cred := credentials.NewTLS(&tls.Config{Certificates: []tls.Certificate{cert},
        ClientAuth:   tls.RequireAndVerifyClientCert,
        ClientCAs:    certPool,
    })

    return cred
}

//GetClientCred 获取客户端证书配置
func GetClientCred() credentials.TransportCredentials {pair, err := tls.LoadX509KeyPair("keys/client.crt", "keys/client.key")
    if err != nil {log.Fatal("LoadX509KeyPair error ", err)
    }
    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("keys/ca.crt")
    if err != nil {log.Fatal("ReadFile ca.crt error ", err)
    }

    if ok := certPool.AppendCertsFromPEM(ca); !ok {log.Fatal("certPool.AppendCertsFromPEM error ")
    }

    cred := credentials.NewTLS(&tls.Config{Certificates: []tls.Certificate{pair},
        ServerName:   "cc.io",
        RootCAs:      certPool,
    })

    return cred
}

GetClientCred 校验客户端 http RESTFUL API 使用

server.go

package main

import (
    "fmt"
    "net/http"

    "gorpc.jtthink.co/helper"

    "google.golang.org/grpc"
    "gorpc.jtthink.co/services"
)

func main() {rpcServer := grpc.NewServer(grpc.Creds(helper.GetServerCred()))

    services.RegisterProdServiceServer(rpcServer, new(services.ProdService))

    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Println(r.Proto)
        fmt.Println(r.Header)
        fmt.Println(r)
        rpcServer.ServeHTTP(w, r)
    })

    httpServer := &http.Server{
        Addr:    ":8081",
        Handler: mux,
    }

    httpServer.ListenAndServeTLS("keys/server.crt", "keys/server.key")
}

httpServer.go

package main

import (
    "context"
    "log"
    "net/http"

    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    "google.golang.org/grpc"
    "gorpc.jtthink.co/helper"
    "gorpc.jtthink.co/services"
)

func main() {ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)

    defer cancel()

    mux := runtime.NewServeMux()

    // 客户端请求时验证
    opts := []grpc.DialOption{grpc.WithTransportCredentials(helper.GetClientCred())}
    err := services.RegisterProdServiceHandlerFromEndpoint(
        ctx,
        mux,
        "localhost:8081",
        opts,
        )

    if err != nil {log.Fatal(err)
    }

    httpServer := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }
    httpServer.ListenAndServe()}

依次启动

go run server.go
go run client.go # grpccli 项目下 

结果

➜ go run client.go
20

启动 httpServer

go run httpServer.go

浏览器访问 http://localhost:8080/v1/prod/123

Go 微服务六  Go - gRPC - TLS 使用 rpc-gatway 不同端口同时提供 rpc 和 http 服务 客户端 rpc 和 http 选其一调用

问题 1: import "google/api/annotations.proto"; 引入爆红 不影响使用,暂为解决 idea 爆红的原因

为题 2:

cannot use mux (type "github.com/grpc-ecosystem/grpc-gateway/runtime".ServeMux) as type "github.com/grpc-ecosystem/grpc-gateway/v2/runtime".ServeMux in argument to services.RegisterProdServiceHandlerFromEndpoint

向 services.RegisterProdServiceHandlerFromEndpoint 传的参数一摸一样,看报错信息分析一下就能知道问题的原因。引入的版本不一致。

将 github.com/grpc-ecosystem/grpc-gateway/runtime 改为 github.com/grpc-ecosystem/grpc-gateway/v2/runtime 即可

正文完
 0