今天在网上看了硬是没找到使用python代码的grpc-gateway,只能试着使用go的grpc-gateway
监听python grpc服务,不过grpc-gateway本身就是一个插件,使用go的话问题应该也不大。
[test@localhost ~]$ useradd test # 新建 test 用户
[test@localhost ~]$ passwd test # 修改密码
[test@localhost ~]$ sudo vim /etc/sudoer # 为 test 用户增加 sudo 权限,使用wq!保存
# 省略前面部分 ...
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
test ALL=(ALL) ALL
# 省略后面部分 ...
[test@localhost ~]$ su - test # 切换至 test 用户
最好是有科学上网,这样下载会快很多。
[test@localhost ~]$ sudo yum install golang -y
[test@localhost ~]$go version
go version go1.13.3 linux/amd64
[test@localhost ~]$ sudo pip3 install grpcio grpcio-tools
[test@localhost ~]$ echo -e "export GOPROXY=https://goproxy.cn\nGOPATH=\$(go env \
GOPATH)\nPATH=\${PATH}:\$(go env GOPATH)/bin" >> ~/.bashrc && source ~/.bashrc
[test@localhost ~]$ curl https://raw.githubusercontent.com/1397436824/\
grpc-gateway-sh/main/install-grpc-gateway.sh | bash
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
[test@localhost ~]$ go get golang.org/dl/go1.17.2@latest
[test@localhost ~]$ ~/go/bin/go1.17.2 download
[test@localhost ~]$ sudo unlink /bin/go
[test@localhost ~]$ sudo ln -s ~/go/bin/go1.17.2 /bin/go
[test@localhost ~]$ go version
go version go1.17.2 linux/arm64
[test@localhost ~]$ mkdir helloworld && cd helloworld
[test@localhost helloworld]$ go mod init github.com/test/myrepo
[test@localhost helloworld]$ mkdir -p proto/helloworld/
[test@localhost helloworld]$ cat > proto/helloworld/helloworld.proto <<EOF
syntax = "proto3";
option go_package = "./;__";
package helloworld;
import "google/api/annotations.proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
EOF
[test@localhost helloworld]$ mkdir -p proto/google/api && cp -r $(go env GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api/{annotations.proto,http.proto} proto/google/api
# 此时结构如下
[test@localhost helloworld]$ tree
.
├── go.mod
└── proto
├── google
│ └── api
│ ├── annotations.proto
│ └── http.proto
└── helloworld
└── helloworld.proto
4 directories, 4 files
# 生成server stubs源码
[test@localhost helloworld]$ python3 -m grpc_tools.protoc -I./proto --python_out=./proto/ --grpc_python_out=./proto/ ./proto/helloworld/helloworld.proto
# 编写grpc服务端,main.py
[test@localhost helloworld]$ cat > main.py <<EOF
from concurrent import futures
import logging
import grpc
from proto.helloworld import helloworld_pb2
from proto.helloworld import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:8080')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()
EOF
# 此时执行 python3 main.py 会报错;
[test@localhost helloworld]$ python3 main.py
Traceback (most recent call last):
File "main.py", line 6, in <module>
from proto.helloworld import helloworld_pb2_grpc
File "/home/test/helloworld/proto/helloworld/helloworld_pb2_grpc.py", line 5, in <module>
from helloworld import helloworld_pb2 as helloworld_dot_helloworld__pb2
ModuleNotFoundError: No module named 'helloworld'
# 解决方法;
[test@localhost helloworld]$ sed -E -i 's/from helloworld /from . /g' /home/test/helloworld/proto/helloworld/helloworld_pb2_grpc.py
# grpc服务端,现在就可以使用python3 main.py运行了
# 此时的目录结构如下
[test@localhost helloworld]$ tree
.
├── main.py
└── proto
├── google
│ └── api
│ ├── annotations.proto
│ └── http.proto
└── helloworld
├── helloworld_pb2_grpc.py
├── helloworld_pb2.py
├── helloworld.proto
└── __pycache__
├── helloworld_pb2.cpython-37.pyc
└── helloworld_pb2_grpc.cpython-37.pyc
5 directories, 8 files
[test@localhost helloworld]$ mkdir -p ./gen/go
[test@localhost helloworld]$ go mod init github.com/test/myrepo
# 生成 gateway的相关源码
[test@localhost helloworld]$ python3 -m grpc_tools.protoc -I./proto --go_out ./gen/go/ --go-grpc_out ./gen/go/ ./proto/helloworld/helloworld.proto
[test@localhost helloworld]$ python3 -m grpc_tools.protoc -I ./proto --grpc-gateway_out=logtostderr=true:./gen/go ./proto/helloworld/helloworld.proto
[test@localhost helloworld]$ go mod tidy
# gateway 网关代码,8081监听8080
[test@localhost helloworld]$ cat > helloworld.gw.go <<EOF
package main
import (
"flag"
"fmt"
"net/http"
gw "github.com/test/myrepo/gen/go"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
var (
echoEndpoint = flag.String("echo_endpoint", "localhost:8080", "endpoint of YourService")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
if err != nil {
return err
}
return http.ListenAndServe(":8081", mux)
}
func main() {
if err := run(); err != nil {
fmt.Print(err.Error())
}
}
EOF
# 此时目录结构如下
[test@localhost helloworld]$ tree
.
├── gen
│ └── go
│ ├── helloworld_grpc.pb.go
│ ├── helloworld.pb.go
│ └── helloworld.pb.gw.go
├── go.mod
├── go.sum
├── helloworld.gw.go
├── main.py
└── proto
├── google
│ └── api
│ ├── annotations.proto
│ └── http.proto
└── helloworld
├── helloworld_pb2_grpc.py
├── helloworld_pb2.py
├── helloworld.proto
└── __pycache__
├── helloworld_pb2.cpython-37.pyc
└── helloworld_pb2_grpc.cpython-37.pyc
7 directories, 14 files
# 运行 grpc-gateway
[test@localhost helloworld]$ go run helloworld.gw.go
# 首先运行
[test@localhost helloworld]$ python3 main.py
# 另开一终端执行
[test@localhost helloworld]$ go run helloworld.gw.go
# 另开一终端执行
[test@localhost helloworld]$ curl -X POST http://localhost:8081/v1/example/echo -d '{"name": "欧力给"}'
{"message":"Hello, 欧力给!"}
# 如果访问没有输出,请将curl 中的 localhost换成具体的IP地址
之后,想必大家可以使用任何grpc支持的语言搭配grpc-gateway使用了吧,套路就是: