gRPC-gateway
参考资料:gRPC-Gateway使用指南
服务中,使用了gRPC gateway(代理)来将外部的http请求映射为内部rpc调用。
proto文件示例:
// 导入google/api/annotations.proto
import "google/api/annotations.proto";
rpc List(ListRequest) returns (ListResponse) {
option (google.api.http) = {
post : "/project/Service/List"
};
}
接下来还需进行一些配置才能完成映射。
示例代码:
(8080端口提供gRPC API服务,8090端口提供HTTP API服务)
import (
"context"
"log"
"net"
"net/http"
helloworldpb "github.com/Q1mi/greeter/proto/helloworld"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime" // 注意v2版本
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
type server struct {
helloworldpb.UnimplementedGreeterServer
}
func NewServer() *server {
return &server{}
}
func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
return &helloworldpb.HelloReply{Message: in.Name + " world"}, nil
}
func main() {
// Create a listener on TCP port
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln("Failed to listen:", err)
}
// 创建一个gRPC server对象
s := grpc.NewServer()
// 注册Greeter service到server
helloworldpb.RegisterGreeterServer(s, &server{})
// 8080端口启动gRPC Server
log.Println("Serving gRPC on 0.0.0.0:8080")
go func() {
log.Fatalln(s.Serve(lis))
}()
// 创建一个连接到我们刚刚启动的 gRPC 服务器的客户端连接
// gRPC-Gateway 就是通过它来代理请求(将HTTP请求转为RPC请求)
conn, err := grpc.DialContext(
context.Background(),
"0.0.0.0:8080",
grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalln("Failed to dial server:", err)
}
gwmux := runtime.NewServeMux()// <--<--
// 注册Greeter
err = helloworldpb.RegisterGreeterHandler(context.Background(), gwmux, conn)
if err != nil {
log.Fatalln("Failed to register gateway:", err)
}
gwServer := &http.Server{
Addr: ":8090",
Handler: gwmux, // <--<-- 该endpoint接收到http请求时,会调用grpc-gateway内部的方法完成映射
}
// 8090端口提供gRPC-Gateway服务
log.Println("Serving gRPC-Gateway on http://0.0.0.0:8090")
log.Fatalln(gwServer.ListenAndServe())
}