首页 > 解决方案 > 如何在 TypeScript 中实现 GRPC 服务器?

问题描述

我正在尝试使用 @grpc/proto-loader 对 protobuf 文件进行动态代码生成,以实现一个简单的服务器,但在 Typescript 中。

我已经做到了

import { Server, loadPackageDefinition, ServerCredentials } from "grpc";
import { loadSync } from "@grpc/proto-loader";

const packageDefinition = loadSync(__dirname + "/protos/ArtifactUpload.proto");
const protoDescriptor = loadPackageDefinition(packageDefinition);
const impl = {
};
const server = new Server();
server.addService(protoDescriptor.ArtifactUpload, impl);
server.bind('0.0.0.0:50051', ServerCredentials.createInsecure());
server.start();

所以我有两个问题

  1. 然而,在他们使用的Javascript 示例protoDescriptor.XXX.service中,没有service属性protoDescriptor.ArtifactUpload
  2. 如果我尝试在 中添加实现方法impl,编译器也无法编译。

由于 Javascript 示例有效,我认为在 Typescript 对象中添加新属性的问题可能能够添加必要的服务类型。但是,到目前为止,我还没有运气。

我的 Protobuf 是

syntax = "proto3";

service ArtifactUpload {
   rpc SignedUrlPutObject (UploadRequest) returns (SignedUrlPutObjectResponse) {}
}

message UploadRequest {
  string message = 1;
}

message SignedUrlPutObjectResponse {
  string reply = 1;
}

标签: node.jstypescriptprotocol-buffersgrpc

解决方案


[2021 年 5 月 14 日更新]:通过 @grpc/proto-loader 生成 TypeScript 现已发布0.6.0版!我在这里更新了我的示例以反映这一点。您现在可以安装最新版本的 proto loader,npm i @grpc/proto-loader其中将包含 TS 生成脚本。以下说明仍然有效。


您可以使用 proto-loader 来生成类型。

首先,安装 proto-loader:

npm i @grpc/proto-loader

然后,您可以像这样生成类型:

./node_modules/.bin/proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/*.proto

这是我用于此示例的 proto 文件:

syntax = "proto3";

package example_package;

message ServerMessage {
  string server_message = 1;
}

message ClientMessage {
  string client_message = 1;
}

service Example {
  rpc unaryCall(ClientMessage) returns (ServerMessage) {}
  rpc serverStreamingCall(ClientMessage) returns (stream ServerMessage) {}
  rpc clientStreamingCall(stream ClientMessage) returns (ServerMessage) {}
  rpc bidirectionalStreamingCall(stream ClientMessage) returns (stream ServerMessage) {}
}

生成类型后,您可以像这样使用它们:

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { ProtoGrpcType } from './proto/example';
import { ClientMessage } from './proto/example_package/ClientMessage';
import { ExampleHandlers } from './proto/example_package/Example';
import { ServerMessage } from './proto/example_package/ServerMessage';

const host = '0.0.0.0:9090';

const exampleServer: ExampleHandlers = {
  unaryCall(
    call: grpc.ServerUnaryCall<ClientMessage, ServerMessage>,
    callback: grpc.sendUnaryData<ServerMessage>
  ) {
    if (call.request) {
      console.log(`(server) Got client message: ${call.request.clientMessage}`);
    }
    callback(null, {
      serverMessage: 'Message from server',
    });
  },

  serverStreamingCall(
    call: grpc.ServerWritableStream<ClientMessage, ServerMessage>
  ) {
    call.write({
      serverMessage: 'Message from server',
    });
  },

  clientStreamingCall(
    call: grpc.ServerReadableStream<ClientMessage, ServerMessage>
  ) {
    call.on('data', (clientMessage: ClientMessage) => {
      console.log(
        `(server) Got client message: ${clientMessage.clientMessage}`
      );
    });
  },

  bidirectionalStreamingCall(
    call: grpc.ServerDuplexStream<ClientMessage, ServerMessage>
  ) {
    call.write({
      serverMessage: 'Message from server',
    });
    call.on('data', (clientMessage: ClientMessage) => {
      console.log(
        `(server) Got client message: ${clientMessage.clientMessage}`
      );
    });
  },
};

function getServer(): grpc.Server {
  const packageDefinition = protoLoader.loadSync('./proto/example.proto');
  const proto = (grpc.loadPackageDefinition(
    packageDefinition
  ) as unknown) as ProtoGrpcType;
  const server = new grpc.Server();
  server.addService(proto.example_package.Example.service, exampleServer);
  return server;
}

if (require.main === module) {
  const server = getServer();
  server.bindAsync(
    host,
    grpc.ServerCredentials.createInsecure(),
    (err: Error | null, port: number) => {
      if (err) {
        console.error(`Server error: ${err.message}`);
      } else {
        console.log(`Server bound on port: ${port}`);
        server.start();
      }
    }
  );
}

我在这里创建了如何将 gRPC 与 TypeScript 一起使用的各种示例:https ://github.com/badsyntax/grpc-js-typescript


推荐阅读