1. 前提
简单地说,RPC 就是调用方采用参数传递的方式,通过调用本机器上的一个函数或方法,去执行远程机器上的函数或方法(可以统称为服务),并返回结果。在整个过程中,RPC 会隐藏具体的通信细节。
RPC的核心是目的是: 本地调用远程(跨内存可访问的)方法。
RPC框架: 开箱即用的实现了RPC调用的框架,其中开源框架如 阿里Dubbo、Google gRPC、Facebook Thrift
远程通信协议: REST(HTTP JSON), SOAP(HTTP XML), gRPC(HTTP2 protobuf)
序列化/反序列化: 文本(XML、JSON)与二进制(Java原生的)与 protobuf
加粗的为这里选用的
2. 准备Proto文件,用于定义统一的接口
文件: hello.proto
syntax = "proto3";
package api;
// 这里可以写服务注释
service HelloWorldService {
// 这里可以写方法注释
rpc SayHello (HelloRequest) returns (HelloResponse) {}
}
// 这里可以写请求结构注释
message HelloRequest {
// 这里可以写参数注释
string name = 1;
}
// 这里可以写响应结构注释
message HelloResponse {
// 这里可以写参数注释
string message = 1;
}
复制代码
3. 准备Python环境
pip install grpcio
pip install grpcio-tools
复制代码
# 编译 proto 文件
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. hello.proto
python -m grpc_tools.protoc: python 下的 protoc 编译器通过 python 模块(module) 实现, 所以说这一步非常省心
--python_out=. : 编译生成处理 protobuf 相关的代码的路径, 这里生成到当前目录
--grpc_python_out=. : 编译生成处理 grpc 相关的代码的路径, 这里生成到当前目录
-I. helloworld.proto : proto 文件的路径, 这里的 proto 文件在当前目录
复制代码
4. 生成如下文件
helloworld_pb2.py: 用来和 protobuf 数据进行交互
helloworld_pb2_grpc.py: 用来和 grpc 进行交互
创建新的文件用来启动grpc服务
服务器端: helloworld_grpc_server.py
from concurrent import futures
import time
import grpc
import hello_pb2
import hello_pb2_grpc
# 实现 proto 文件中定义的 HelloWorldServiceServicer
class Greeter(hello_pb2_grpc.HelloWorldServiceServicer):
# 实现 proto 文件中定义的 rpc 调用
def SayHello(self, request, context):
return hello_pb2.HelloResponse(message = 'hello {msg}'.format(msg = request.name))
def serve():
# 启动 rpc 服务
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_HelloWorldServiceServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(60*60*24) # one day in seconds
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()
复制代码
python helloworld_grpc_server.py
启动服务
到此python服务端启动完成,监听50051端口
5. 生成前端代码
生成grpc-web client代码
在windows下处理起来比较麻烦,直接使用win10 子系统处理了,bash如下
# 下载protoc
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.17.3/protoc-3.17.3-linux-x86_64.zip
# 解压
unzip protoc-3.17.3-linux-x86_64.zip -d protoc
cd protoc/
# 拷贝protoc.exe到path
sudo mv bin/protoc /usr/local/bin
cd ..
# 下载protoc-gen-grpc-web
wget https://github.com/grpc/grpc-web/releases/download/1.2.1/protoc-gen-grpc-web-1.2.1-linux-x86_64
sudo mv protoc-gen-grpc-web-1.2.1-linux-x86_64 /usr/local/bin/protoc-gen-grpc-web
复制代码
生成代码
js版本:
protoc -I=. --js_out=import_style=commonjs:. --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. hello.proto
ts版本:
protoc -I=. --js_out=import_style=commonjs:. --grpc-web_out=import_style=typescript,mode=grpcwebtext:. hello.proto
复制代码
前端项目安装依赖
yarn add grpc-web
yarn add google-protobuf
复制代码
把生成的2个js文件直接丢到node_modules 里
Vue模板
<template>
<div className="home">
{{ message }}
</div>
</template>
<script>
import { HelloRequest } from 'hello_pb'
import { HelloWorldServicePromiseClient } from 'hello_grpc_web_pb'
export default {
name: 'Home',
data () {
return {
message: ''
}
},
methods: {
// 获取消息(使用async await)
async getMessage () {
// 注意这个端口是代理服务器的端口,不是grpc的端口
var client = new HelloWorldServicePromiseClient('http://localhost:8080', null, null)
// simple unary call
var request = new HelloRequest()
request.setName('World')
// eslint-disable-next-line handle-callback-err
const res = client.sayHello(request, {}, (err, response) => {
// document.getElementById('response').innerHTML = response.getMessage()
})
res.then(res => {
console.log(res)
})
}
},
mounted () {
this.getMessage()
}
}
</script>
复制代码
6. 部署代理
由于Grpc使用的Http2 这里需要部署一代理进行处理,同时解决跨域问题
grpcwebproxy-v0.14.0-win64.exe --backend_addr=localhost:50051 --run_tls_server=false --allow_all_origins
7. 愉快运行
最后就可以愉快的进行交互了
后续我还会在学习学习用法….
参考文章: