快速入门

本指南通过一个简单的工作示例帮助你快速入门 gRPC-Web。

前提条件

需要 Docker 和支持 Docker Compose 文件版本 3 的 docker-compose。有关安装说明,请参阅 安装 Compose

获取示例代码

示例代码是 grpc-web 仓库的一部分。

  1. 下载仓库的压缩文件 并解压,或克隆该仓库:

    git clone https://github.com/grpc/grpc-web
  2. 切换到仓库的根目录:

    cd grpc-web

在浏览器中运行 Echo 示例!

grpc-web 目录:

  1. 获取所需的包和工具:

    docker-compose pull prereqs node-server envoy commonjs-client

    如果看到以下警告,可以忽略它,运行示例应用时不会影响:

    WARNING: Some service image(s) must be built from source
  2. 将服务作为后台进程启动:

    docker-compose up -d node-server envoy commonjs-client
  3. 从你的浏览器访问:

    • 访问 localhost:8081/echotest.html

    • 在文本输入框中输入一条消息,如 “Hello”。

    • 点击发送按钮。

你将看到服务器回显的消息显示在输入框下方。

恭喜!你刚刚运行了一个基于 gRPC 的客户端-服务器应用。

完成后,通过运行以下命令关闭之前启动的服务:

docker-compose down

发生了什么?

这个示例应用有三个关键组件:

  1. node-server:标准的 gRPC 服务器,使用 Node 实现。该服务器监听端口 :9090,并实现应用的业务逻辑(回显客户端消息)。

  2. envoy:Envoy 代理。它监听端口 :8080,并将浏览器的 gRPC-Web 请求转发到端口 :9090

  3. commonjs-client:该组件使用 protoc-gen-grpc-web 插件生成客户端存根类,使用 webpack 编译所有 JS 依赖,并通过简单的 Web 服务器在端口 :8081 提供静态内容(echotest.htmldist/main.js)。用户从网页输入的消息会作为 gRPC-Web 请求发送到 Envoy 代理。

基础教程

这是一个关于如何在浏览器中使用 gRPC-Web 的基本教程。

通过本教程,您将学习如何:

  • .proto 文件中定义服务。

  • 使用协议缓冲区编译器生成客户端代码。

  • 使用 gRPC-Web API 为您的服务编写一个简单的客户端。

本教程假设您对 协议缓冲区 有基本的了解。

为什么使用 gRPC 和 gRPC-Web?

使用 gRPC,您可以在 .proto 文件中定义服务一次,并在任何支持的语言中实现客户端和服务器,这些客户端和服务器可以在从大数据中心内的服务器到您自己的平板电脑等各种环境中运行 —— 所有不同语言和环境之间通信的复杂性都由 gRPC 处理。您还将获得使用协议缓冲区的所有优势,包括高效的序列化、简单的接口描述语言(IDL)和轻松的接口更新。gRPC-Web 让您可以使用符合规范的 API 从浏览器访问以这种方式构建的 gRPC 服务。

定义服务

创建 gRPC 服务的第一步是使用协议缓冲区定义服务方法及其请求和响应消息类型。在本示例中,我们在名为 echo.proto 的文件中定义了我们的 EchoService。有关协议缓冲区和 proto3 语法的更多信息,请参阅 协议缓冲区文档

message EchoRequest {
  string message = 1;
}

message EchoResponse {
  string message = 1;
}

service EchoService {
  rpc Echo(EchoRequest) returns (EchoResponse);
}

实现 gRPC 后端服务器

接下来,我们使用 Node 实现我们的 EchoService 接口作为后端的 gRPC EchoServer。这个服务器将处理来自客户端的请求。详情请参见文件 node-server/server.js

您可以使用任何支持 gRPC 的语言来实现服务器。有关更多信息,请参见 主页

function doEcho(call, callback) {
  callback(null, {message: call.request.message});
}

配置 Envoy 代理

在本示例中,我们将使用 Envoy 代理将浏览器的 gRPC 请求转发到后端服务器。完整的配置文件可以在 envoy.yaml 中查看。

要将 gRPC 请求转发到后端服务器,我们需要一个如下的配置块:

admin:
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: echo_service }
          http_filters:
          - name: envoy.grpc_web
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
  - name: echo_service
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options: {}
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: echo_service
      endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: node-server
                  port_value: 9090

您可能还需要添加一些 CORS 设置,以确保浏览器能够请求跨域内容。

在这个简单的示例中,浏览器会向端口 8080 发起 gRPC 请求。Envoy 会将请求转发到监听在端口 9090 的后端 gRPC 服务器。

生成 Protobuf 消息和服务客户端存根

要从 echo.proto 生成 protobuf 消息类,运行以下命令:

protoc -I=$DIR echo.proto \
  --js_out=import_style=commonjs:$OUT_DIR

传递给 --js_out 标志的 import_style 选项确保生成的文件将具有 CommonJS 风格的 require() 语句。

要生成 gRPC-Web 服务客户端存根,首先需要 gRPC-Web protoc 插件。要编译插件 protoc-gen-grpc-web,您需要在仓库根目录下运行以下命令:

cd grpc-web
sudo make install-plugin

然后,运行以下命令生成服务客户端存根文件:

protoc -I=$DIR echo.proto \
  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:$OUT_DIR

在上面的 --grpc-web_out 参数中:

  • mode 可以是 grpcwebtext(默认)或 grpcweb

  • import_style 可以是 closure(默认)或 commonjs

我们的命令将默认生成名为 echo_grpc_web_pb.js 的客户端存根。

编写 JS 客户端代码

现在您可以编写一些 JS 客户端代码。将其放入 client.js 文件中。

const {EchoRequest, EchoResponse} = require('./echo_pb.js');
const {EchoServiceClient} = require('./echo_grpc_web_pb.js');

var echoService = new EchoServiceClient('http://localhost:8080');

var request = new EchoRequest();
request.setMessage('Hello World!');

echoService.echo(request, {}, function(err, response) {
  // ...
});

您需要一个 package.json 文件:

{
  "name": "grpc-web-commonjs-example",
  "dependencies": {
    "google-protobuf": "^3.6.1",
    "grpc-web": "^0.4.0"
  },
  "devDependencies": {
    "browserify": "^16.2.2",
    "webpack": "^4.16.5",
    "webpack-cli": "^3.1.0"
  }
}

编译 JS 库

最后,将所有相关的 JS 文件编译成一个可以在浏览器中使用的单一 JS 库。

npm install
npx webpack client.js

现在,将 dist/main.js 嵌入到您的项目中并查看其效果!