闽公网安备 35020302035485号
$ go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 堆代码 duidaima.com
syntax = "proto3";
package ecommerce;
import "google/protobuf/wrappers.proto";
option go_package = "/ecommerce";
service OrderManagement {
rpc getOrder(google.protobuf.StringValue) returns (Order);
rpc addOrder(Order) returns (google.protobuf.StringValue);
}
message Order {
string id = 1;
repeated string items = 2;
string description = 3;
float price = 4;
google.protobuf.StringValue destination = 5;
}
目前有三种方式可以反向代理服务器:3.使用外部配置,比较适用于不能修改源protobuf的情况下
syntax = "proto3";
package ecommerce;
option go_package = "ecommerce/";
import "google/protobuf/wrappers.proto";
import "google/api/annotations.proto";
service OrderManagement {
rpc getOrder(google.protobuf.StringValue) returns (Order){
option(google.api.http) = {
get: "/v1/getOrder"
};
}
}
message Order {
string id = 1;
repeated string items = 2;
string description = 3;
float price = 4;
string destination = 5;
}
pb ├── google │ └── api │ ├── annotations.proto │ └── http.proto └── product.proto之后执行protoc来生成代码。
protoc -I ./pb \ --go_out ./ecommerce --go_opt paths=source_relative \ --go-grpc_out ./ecommerce --go-grpc_opt paths=source_relative \ --grpc-gateway_out ./ecommerce --grpc-gateway_opt paths=source_relative \ ./pb/product.proto生成出来的代码,对比非gRPC-Gateway的版本会多出了一个*.gw.pb.go文件。
buf mod initbuf命令会创建buf.yaml文件,在此文件中添加依赖buf.build/googleapis/googleapis
version: v1
breaking:
use:
- FILE
lint:
use:
- DEFAULT
## add
deps:
- buf.build/googleapis/googleapis
2. 更新依赖buf mod updatebuf命令从Buf Schema Registry (BSR)[2]中获取依赖,把你所有的 deps 更新到最新版。并且会生成 buf.lock 来固定版本
pb ├── buf.lock ├── buf.yaml └── product.proto3.创建一个buf.gen.yaml
version: v1
plugins:
- plugin: go
out: ecommerce
opt:
- paths=source_relative
- plugin: go-grpc
out: ecommerce
opt:
- paths=source_relative
- name: grpc-gateway
out: ecommerce
opt:
- paths=source_relative
- generate_unbound_methods=true
4.生成代码buf generate pb执行的效果和上文中protoc命令一样
package main
import (
"context"
"net"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
pb "github.com/liangwt/note/grpc/ecosystem/grpc-gateway/ecommerce"
"google.golang.org/grpc"
)
func main() {
grpcPort, gwPort := ":8009", ":8010"
go func() {
lis, err := net.Listen("tcp", grpcPort)
if err != nil {
panic(err)
}
s := grpc.NewServer()
pb.RegisterOrderManagementServer(s, &OrderManagementImpl{})
if err := s.Serve(lis); err != nil {
panic(err)
}
}()
// 建立一个到gRPC Port的连接
conn, err := grpc.DialContext(
context.Background(),
"127.0.0.1"+grpcPort,
grpc.WithBlock(),
grpc.WithInsecure(),
)
if err != nil {
panic(err)
}
gwmux := runtime.NewServeMux()
err = pb.RegisterOrderManagementHandler(context.Background(), gwmux, conn)
if err != nil {
panic(err)
}
http.ListenAndServe(gwPort, gwmux)
// 以下和http.ListenAndServe(gwPort, gwmux)等价
// gwServer := &http.Server{
// Addr: gwPort,
// Handler: gwmux,
// }
// if err := gwServer.ListenAndServe(); err != nil {
// panic(err)
// }
}
2.还有一种方式不依赖grpc服务,以本地函数调用的方式实现。package main
import (
"context"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
pb "github.com/liangwt/note/grpc/ecosystem/grpc-gateway/ecommerce"
)
func main() {
gwmux := runtime.NewServeMux()
err := pb.RegisterOrderManagementHandlerServer(context.Background(), gwmux, &OrderManagementImpl{})
if err != nil {
panic(err)
}
http.ListenAndServe(":8010", gwmux)
}
$ curl -s -X GET \
'127.0.0.1:8010/v1/getOrder?value=101' \
--header 'Accept: */*' | jq
{
"id": "101",
"items": [
"Google",
"Baidu"
],
"description": "example",
"price": 0,
"destination": "example"
}
这里有个细节需要注意,google.protobuf.StringValue在映射到HTTP的时候默认参数名为value,所以访问时请求参数写成value=101service OrderManagement {
rpc getOrder(google.protobuf.StringValue) returns (Order){
option(google.api.http) = {
get: "/v1/getOrder"
};
}
}
service OrderManagement {
rpc getOrder(google.protobuf.StringValue) returns (Order){
option(google.api.http) = {
get: "/v1/getOrder/{value}"
};
}
}
curl -X GET \
'127.0.0.1:8010/v1/getOrder/101' \
--header 'Accept: */*' \
我们还可以给参数设定个名字service OrderManagement {
rpc getOrder(getOrderReq) returns (Order){
option(google.api.http) = {
get: "/v1/getOrder"
};
}
}
message getOrderReq {
google.protobuf.StringValue id = 1;
}
curl -X GET \
'127.0.0.1:8010/v1/getOrder?id=101' \
--header 'Accept: */*' \
依旧可以把参数放到path中service OrderManagement {
rpc getOrder(getOrderReq) returns (Order){
option(google.api.http) = {
get: "/v1/getOrder/{id}"
};
}
}
message getOrderReq {
google.protobuf.StringValue id = 1;
}
curl -X GET \
'127.0.0.1:8010/v1/getOrder/101' \
--header 'Accept: */*' \
syntax = "proto3";
package ecommerce;
import "google/protobuf/wrappers.proto";
import "google/api/annotations.proto";
option go_package = "/ecommerce";
service OrderManagement {
rpc getOrder(google.protobuf.StringValue) returns (Order) {
option (google.api.http) = {
get : "/v1/getOrder"
};
}
rpc addOrder1(Order) returns (google.protobuf.StringValue) {
option (google.api.http) = {
post : "/v1/addOrder1"
body : "*"
};
}
rpc addOrder2(OrderRequest) returns (google.protobuf.StringValue) {
option (google.api.http) = {
post : "/v1/addOrder2"
body : "order"
};
}
}
message OrderRequest {
Order order = 1;
}
message Order {
string id = 1;
repeated string items = 2;
string description = 3;
float price = 4;
google.protobuf.StringValue destination = 5;
}
1.对于addOrder1接口$ curl -s -X POST \
'127.0.0.1:8010/v1/addOrder1' \
--header 'Accept: */*' \
--data '{"id": "102","items": ["Google","Baidu"],"description": "example","price": 0,"destination": "example"}'
2.对于addOrder2接口$ curl -s -X POST \
'127.0.0.1:8010/v1/addOrder2' \
--header 'Accept: */*' \
--data '{"id": "102","items": ["Google","Baidu"],"description": "example","price": 0,"destination": "example"}'
func main() {
gwmux := runtime.NewServeMux()
err := pb.RegisterOrderManagementHandlerServer(context.Background(), gwmux, &OrderManagementImpl{})
if err != nil {
panic(err)
}
err = gwmux.HandlePath("GET", "/hello/{name}", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
w.Write([]byte("hello " + pathParams["name"]))
})
http.ListenAndServe(":8010", gwmux)
}
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest2. 生成swagger文件
protoc -I ./pb --openapiv2_out ./doc --openapiv2_opt logtostderr=true \
./pb/product.proto
当然更推荐使用buf工具version: v1
plugins:
- plugin: go
out: ecommerce
opt:
- paths=source_relative
- plugin: go-grpc
out: ecommerce
opt:
- paths=source_relative
- name: grpc-gateway
out: ecommerce
opt:
- paths=source_relative
- generate_unbound_methods=true
- name: openapiv2
out: doc
opt:
- logtostderr=true
于是便可以得到doc/product.swagger.json文件