Web gRPC 是 gRPC 在 Web 上的一个适配实现。关于他的介绍以及为什么要用 gRPC 就不在这解释了,如果你决定使用 Web gRPC,并且正在寻找前端的库和解决方案,看一看这篇文章,应该会有所帮助。
gRPC 的使用方案有很多,每种方案方法都有各自的特点,也有各自的优缺点。
接下来会列举三种接入方案
- google-protobuf + grpc-web-client
- grpc-web (最近发布)
- protobufjs + webpack loader + grpc-web-client + polyfill (目前在用)
1. google-protobuf + grpc-web-client
google-protobuf 是 google 提供的 protobuf 文件的编译工具,可以将 protobuf 编译成各种语言,我们用它来编译成 js 文件。
grpc-web-client 则可以执行 google-protobuf 生成的 js,调用远程 rpc 服务。
使用步骤
- 编译文件
protoc --js_out=import_style=commonjs,binary:. messages.proto base.proto
复制代码
- 引入 js 代码
import {grpc} from "grpc-web-client";
// Import code-generated data structures.
import {BookService} from "../_proto/examplecom/library/book_service_pb_service";
import {QueryBooksRequest, Book, GetBookRequest} from "../_proto/examplecom/library/book_service_pb";
复制代码
- 创建请求对象
const queryBooksRequest = new QueryBooksRequest();
queryBooksRequest.setAuthorPrefix("Geor");
复制代码
- 执行 grpc 方法调用服务
grpc.invoke(BookService.QueryBooks, {
request: queryBooksRequest,
host: "https://example.com",
onMessage: (message: Book) => {
console.log("got book: ", message.toObject());
},
onEnd: (code: grpc.Code, msg: string | undefined, trailers: grpc.Metadata) => {
if (code == grpc.Code.OK) {
console.log("all ok")
} else {
console.log("hit an error", code, msg, trailers);
}
}
});
复制代码
封装代码
封装 invoke 方法
封装 grpc.invoke
方法,一方面可以统一处理 host,header,错误,增加 log 等 另一方面可以改造成 Promise,方便调用
/**
* @classdesc GrpcClient
* grpc客户端
*/
class GrpcClient {
constructor(config) {
this.config = extend({}, DEFAULT_CONFIG, config || {})
}
/**
* 执行grpc方法调用
* @param methodDescriptor 方法定义描述对象
* @param params 请求参数对象
* @return {Promise}
*/
invoke(methodDescriptor, params = {}) {
let host = this.config.baseURL
let RequestType = methodDescriptor.requestType || Empty
let request = params.$request || new RequestType(), headers = {}
let url = host + '/' + methodDescriptor.service.serviceName + '/' + methodDescriptor.methodName
return new Promise((resolve, reject) => {
// eslint-disable-next-line no-console
this.config.debug && console.log('[Grpc.Request]:', url, request.toObject())
grpc.invoke(methodDescriptor, {
headers,
request,
host,
onMessage: (message) => {
resolve(message)
},
onEnd: (code, message, trailers) => {
if (code !== grpc.Code.OK) {
message = message || grpc.Code[code] || ''
const err = new Error()
extend(err, { code, message, trailers })
return reject(err)
}
},
})
}).then((message) => {
// eslint-disable-next-line no-console
this.config.debug && console.log('[Grpc.Response]:', url, message.toObject())