【问题标题】:Cannot import google's proto with @grpc/proto-loader无法使用@grpc/proto-loader 导入谷歌的原型
【发布时间】:2019-03-18 02:57:38
【问题描述】:

我有以下原型:

syntax = "proto3";

import "google/rpc/status.proto";

message Response {   
    google.rpc.Status status = 1;
}

message Request {   
    Type name = 1;
}

service Service {
    rpc SomeMethod (Request) returns (Response);
}

我正在节点中编写一个客户端:

    const path = require('path');
    const grpc = require('grpc');
    const protoLoader = require('@grpc/proto-loader');
    const protoFiles = require('google-proto-files');

    const PROTO_PATH = path.join(__dirname, '/proto/myproto.proto');

    const packageDefinition = protoLoader.loadSync(
      PROTO_PATH,
      {
        keepCase: true,
        longs: String,
        enums: String,
        defaults: true,
        oneofs: true,
        includeDirs: [protoFiles('rpc')],
      },
    );

    const proto = grpc.loadPackageDefinition(packageDefinition);
    const client = new proto.Service('localhost:1111', grpc.credentials.createInsecure());

当我运行客户端时,我收到以下错误:TypeError: proto.Service is not a constructor。我发现它与status.proto的导入有关。使用 proto-loader 导入 google protos 的正确方法是什么?服务器是 Java 语言。

【问题讨论】:

    标签: node.js grpc protocol-buffers grpc-node


    【解决方案1】:

    这里的问题是protoFiles('rpc') 返回的路径不适用于您的.proto 文件中的import 行。该导入行意味着@grpc/proto-loader 正在寻找包含google/rpc/status.proto 的包含目录,但protoFiles('rpc') 返回一个直接包含status.proto 的目录。因此,您必须更改其中一项或两项,以便相关目录正确匹配。

    【讨论】:

    • 更改为 const IMPORT_PATH = path.join(__dirname, '/../node-modules/google-proto-files');和 includeDirs: [IMPORT_PATH],但得到相同的错误 - 服务不是构造函数。
    • 好的,我已经能够确认这里还有其他问题。我仍然相当有信心,我提到的问题是问题的一部分。
    • 我知道问题在于导入,因为我可以在不使用 status.proto 的情况下成功创建客户端(已注释掉),但我无法找到如何正确加载 google protos 的任何地方。
    【解决方案2】:

    Olga,如果您使用的是 includeDirs,则不能在 PROTO_PATH 中使用绝对路径。显然,您需要将两个路径(即 myproto.proto 的路径和 google-proto-files 的路径)都放入 includeDirs 并仅使用文件名作为 PROTO_PATH ,然后它就可以正常工作了。见这里:

    https://github.com/grpc/grpc-node/issues/470

    这里是修改后的代码。请注意,我还必须在 myproto.proto 中将“Type”替换为“int32”。

    const path = require('path');
    const grpc = require('grpc');
    const protoLoader = require('@grpc/proto-loader');
    const protoFiles = require('google-proto-files');
    
    const PROTO_PATH = 'myproto.proto';
    
    const packageDefinition = protoLoader.loadSync(
      PROTO_PATH,
      {
        keepCase: true,
        longs: String,
        enums: String,
        defaults: true,
        oneofs: true,
        includeDirs: ['node_modules/google-proto-files', 'proto']
        },
      );
    
    const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
    const client = new protoDescriptor.Service('localhost:1111',  grpc.credentials.createInsecure());
    

    希望对您有所帮助。 :)

    【讨论】:

    • 使用绝对路径: const IMPORT_PATH = path.join(__dirname, '/proto'); const GOOGLE_PROTOS = path.join(__dirname, '../node_modules/google-proto-files');并包含目录:[GOOGLE_PROTOS, IMPORT_PATH]
    • 是的,但这就是我的意思。如果您还指定了 includeDirs 参数,则不能在第一个参数中使用绝对路径,即要加载的主 proto 文件。至于 includeDirs 元素本身,您可以随意使用相对路径或绝对路径。这应该记录在 loadSync() 警告或实现细节部分,恕我直言。
    • 不适用于 insludeDirs 中的相对路径,仅适用于绝对路径。
    • 我是那个包的维护者。这个约束没有被记录,因为它实际上是如何处理includeDirs 的一个错误。至于相对 includeDirs 路径,我建议不要使用它们,因为这些路径可能与您期望它们相对的路径不相关。
    猜你喜欢
    • 2019-05-07
    • 2018-03-26
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 2022-06-11
    • 1970-01-01
    • 2023-01-16
    相关资源
    最近更新 更多