grpc 具备多种常用的功能,比如 Authentication、Flow Control 等等。
grpc-ecosystem 中有多个和 grpc 相关的生态项目,比如:
grpc-gateway 根据 proto 文件生成处理 http 请求的代码,这写代码将收到的 http 请求转换成对 grpc 服务的调用。
用注解标记映射关系需要更改接口定义文件。如果不能修改接口定义文件,可以:
具体用法见:gRPC API Configuration。
如果使用注解标记,需要将下面的文件复制到本地项目 idl 目录的 google/api 中,就可以使用其中的 option google.api.http 进行标注。
google.api.http 支持参数都列在 google/api/http.proto 中的 HttpRule 结构体中,用途分别如下:
message HttpRule {
string selector = 1;
oneof pattern {
string get = 2;
string put = 3;
string post = 4;
string delete = 5;
string patch = 6;
CustomHttpPattern custom = 8;
}
string body = 7;
string response_body = 12;
repeated HttpRule additional_bindings = 11;
}
路径参数指定方式如下(example/library/v1/library.proto),定义了两个路径参数 schelves 和 books,其中 schelves 对应请求参数中的 name。Google 的 api 使用了这种风格的路径参数:google api。
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{name=shelves/*/books/*}"
};
option (google.api.method_signature) = "name";
}
代码生成需要在 protoc-gen-go 和 protoc-gen-go-grpc 之外,再安装两个 protoc 插件:
go install \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest \
然后用 protoc 生成转换 http 请求的代码:
protoc -I ./idl --grpc-gateway_out ./ \
--grpc-gateway_opt module=NAME \
./idl/NAME/v1beta/*.proto \
./idl/NAME/v1beta/*/*.proto
然后在 grpc 服务中启动一个 http 服务注入生成的 handler
func RunHttpServer(ctx context.Context, services []Service) {
mux := runtime.NewServeMux(
runtime.WithIncomingHeaderMatcher(func(key string) (string, bool) {
return runtime.DefaultHeaderMatcher(key)
}),
runtime.WithOutgoingHeaderMatcher(func(key string) (string, bool) {
return key, true
}),
runtime.WithOutgoingTrailerMatcher(func(key string) (string, bool) {
return key, true
}),
)
opts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
grpc.WithChainUnaryInterceptor(interceptor.ClientTraceUnary),
grpc.WithChainStreamInterceptor(interceptor.ClientTraceStream)}
err = frontend.RegisterFrontendApiServiceHandlerFromEndpoint(ctx, mux, conf.GetHTTPBackend()/*grpc服务的地址*/, opts)
if err != nil {
utils.FATAL(ctx, "failed to register http handler", map[string]interface{}{"err": err, "srv": srv})
}
utils.INFO(ctx, "http listening at "+conf.GetHTTPListenAddr(), nil)
if err = http.ListenAndServeTLS(conf.GetHTTPListenAddr(), conf.GetHTTPCert(), conf.GetHTTPKey(), mux); err != nil {
utils.FATAL(ctx, "http serve fail", map[string]interface{}{"err": err})
}
}
指定服务在 proto 文件,生成一个 swagger 格式的接口说明文件:
protoc -I ./idl --openapiv2_out ./ \
--openapiv2_opt output_format=json \
./idl/NAME/v1beta/*.proto \