gRPC-Gateway是gRPC生态的一环,用于对HTTP协议的扩展,是一套高性能、高扩展的开源RPC框架。
因此,要掌握gRPC-Gateway,必须要对gRPC有一定的基础,才能明白它的定位与价值。
整个方案分为两个方向:
三个模块:
两个协议:
关键点:
stub这个单词很有意思,相对准确的翻译是存根、残端,和面向对象中的 接口 有异曲同工之妙:提供了实现的框架,但具体实现仍交由开发者。
对开发者来说,整个方案的工作分为两部分:
proto
文件stub
的实现我们看一个官方github上的示例proto
文件:
syntax = "proto3";
package your.service.v1;
option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1";
import "google/api/annotations.proto";
message StringMessage {
string value = 1;
}
service YourService {
rpc Echo(StringMessage) returns (StringMessage) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
我们从上到下,对里面的语法做简单的分析:
如何将proto文件生成为Go语言的stub
代码,官方提供了两个路径:
具体的操作方法可以参考:https://github.com/grpc-ecosystem/grpc-gateway#usage 。
代码生成的只是一个stub
,具体实现需要我们自己编码。上述方法生成的函数签名大致如下:
func Echo(ctx context.Context, request *proto.StringMessage) returns (response *proto.StringMessage, err error){
// 自己实现的业务逻辑
}
关于其中的context与error,我在上一讲已经讲过大致的规范。而在gRPC-Gateway中怎么使用呢?我们会在具体示例中再去讲。
1~3步骤将一个RPC请求的开发过程串联了起来,作为web服务的高频迭代部分。
但如果要作为一个完整的服务,还需要包括基础的server启动代码,很少需要改动。我们接着看官方的示例代码:
package main
import (
"context"
"flag"
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
gw "github.com/yourorg/yourrepo/proto/gen/go/your/service/v1/your_service" // Update
)
var (
// command-line options:
// gRPC server endpoint
grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:9090", "gRPC server endpoint")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Register gRPC server endpoint
// Note: Make sure the gRPC server is running properly and accessible
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
if err != nil {
return err
}
// Start HTTP server (and proxy calls to gRPC server endpoint)
return http.ListenAndServe(":8081", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
我们要明确一点:这部分代码并没有包括gRPC服务的启动代码,它已经默认在grpcServerEndpoint
这个地址+端口上启动了。如果没有进程隔离的强要求,我们可以在main
函数中同时启动 gRPC server和gRPC-Gateway server。
gRPC-Gateway启动时有4个重要参数:
关于gRPC部分内容可以参考:https://grpc.io/docs/languages/go/quickstart/
整套框架的完整示例可以参考这个文件 - https://github.com/Junedayday/micro_web_service/blob/master/main.go
本篇重点是对gRPC-Gateway最基础的原理和使用进行了分析。
如果你能通过本篇文章,对这个方案有一个基本认识,那么接下来我会带你玩转这个框架。你也无需担心无法实践到日常项目中:gRPC-Gateway中的能力与gin等框架都是共通的,可以轻松地举一反三。
Github: https://github.com/Junedayday/code_reading Blog: http://junes.tech/ Bilibili: https://space.bilibili.com/293775192