【问题标题】:Can I send a custom Error message from server to client GRPC?我可以从服务器向客户端 GRPC 发送自定义错误消息吗?
【发布时间】:2017-04-08 05:07:52
【问题描述】:

我创建了一个简单的 GRPC 服务器和客户端。

我想做的是在服务器中创建一个自定义错误并将其传递给客户端。我的代码如下所示:

Server.js

var error = require('error');

var PROTO_PATH = grpc.load(__dirname + '/proto/hello.proto');
var hello_proto = PROTO_PATH.hello;

function sayHello(call, callback) {

    try {
        var jsErr = new Error('MY_ERROR');
        jsErr.newStatus = 401;
        jsErr.newMessage = 'custom unAuthorized error';
        console.log(Object.getOwnPropertyNames(jsErr));
        console.log(jsErr);
        callback(jsErr);

    } catch(e) {
        callback(e);
    }
}

function sayHelloAgain(call, callback) {
    callback(null, {message: 'Hello Again ' + call.request.name});
}

function main() {

    var server = new grpc.Server();
    server.addProtoService(hello_proto.Hello.service, {sayHello: sayHello,sayHelloAgain: sayHelloAgain });
    server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
    server.start();
}

main();

Client.js

var grpc = require('grpc');

var PROTO_PATH = grpc.load(__dirname + '/proto/hello.proto');
var hello_proto = PROTO_PATH.hello;

function main() {
    var client = new hello_proto.Hello('localhost:50051',grpc.credentials.createInsecure());
    var user;
    if (process.argv.length >= 3) {
        user = process.argv[2];
    } else {
        user = 'world';
    }

    client.sayHello({name: user}, function(err, response) {

        console.log(Object.getOwnPropertyNames(err));
        console.log(err);
    });
}

main();

还有我的原型文件

syntax = "proto3";

package hello;

service Hello {
    rpc sayHello(sayHelloRequest) returns (sayHelloResponse) {}
    rpc sayHelloAgain(sayHelloRequest) returns (sayHelloResponse) {}
}


message sayHelloRequest {
    string name = 1;
}

message sayHelloResponse {
    string message = 1;
}

当我运行cient时,每个结果看起来像这样

服务器。

[ 'stack', 'message', 'newStatus', 'newMessage' ]
{ [Error: MY_ERROR] newStatus: 401, newMessage: 'custom unAutorized error' }

客户。

[ 'stack', 'message', 'code', 'metadata' ]
{ [Error: MY_ERROR] code: 2, metadata: Metadata { _internal_repr: {} } }

所以我创建的自定义 javascript 错误的 newStatus, newMessage 属性已删除,它已转换为 GRPC 标准错误消息。

我的问题是

  1. 是否可以向客户端发送自定义消息?
  2. 我可以创建 GRPC 错误,而不是 javascript 错误吗?
  3. 我认为向客户端发送自定义属性的一种方法是将自定义数据添加到Metadata。但我也不知道该怎么做。

【问题讨论】:

    标签: javascript node.js protocol-buffers grpc


    【解决方案1】:

    根据ServerErrorResponse 的定义,您可以将其作为callback 中的第一个参数返回,您可以为此创建简单的函数(TypeScript)。

    function grpcError(): ServerErrorResponse {
        return {
            message: 'Something wrong', // required param
            name: 'Error',              // required param
            code: Status.UNKNOWN,       // code: 2
            metadata: undefined,
            details: undefined,
            stack: undefined,
         };
    };
    

    Status 是从 0 到 16 的枚举

    export declare enum Status {
        OK = 0,
        CANCELLED = 1,
        UNKNOWN = 2,
        INVALID_ARGUMENT = 3,
        DEADLINE_EXCEEDED = 4,
        NOT_FOUND = 5,
        ALREADY_EXISTS = 6,
        PERMISSION_DENIED = 7,
        RESOURCE_EXHAUSTED = 8,
        FAILED_PRECONDITION = 9,
        ABORTED = 10,
        OUT_OF_RANGE = 11,
        UNIMPLEMENTED = 12,
        INTERNAL = 13,
        UNAVAILABLE = 14,
        DATA_LOSS = 15,
        UNAUTHENTICATED = 16
    }
    

    所以服务器的示例代码是

    let error = grpcError();
    error.message = "YOUR CUSTOM ERROR MESSAGE";
    callback(error, null);
    

    对于客户

    client.sayHello({name: user}, function(err, response) {
        console.log(err);
    });
    

    输出类似于

    Error: 2 UNKNOWN: YOUR CUSTOM ERROR MESSAGE
    // stacktrace
    {
      code: 2,
      details: 'YOUR CUSTOM ERROR MESSAGE',
      metadata: Metadata { internalRepr: Map(0) {}, options: {} }
    }
    

    【讨论】:

      【解决方案2】:

      在 gRPC Google Group 上有对同样问题的有用回复: https://groups.google.com/d/msg/grpc-io/X_bUx3T8S7s/x38FU429CgAJ

      您可以使用错误向客户端发送自定义状态消息 对象的消息属性。在您的示例中,即“MY_ERROR”。这 状态码应该在“code”属性中,就像你看到的一样 在客户端。

      如果你想使用 gRPC 状态结构而不是 JavaScript 错误,您可以通过填充“代码”属性和 对象的“消息”或“详细信息”属性。

      如果你想发送元数据,你应该构造一个 grpc.Metadata 类,然后将键/值对添加到结果对象。 然后你可以将它作为回调的第三个参数传递或设置 错误的“元数据”属性将其发送到错误的客户端。

      请注意,gRPC 使用的状态码不是 HTTP 状态 代码,但在 grpc.status 中定义的 gRPC 特定代码。你 应该只使用这些代码设置错误的代码属性。如果你 想要发送您自己的代码,请改用元数据。

      我会用一些例子来说明上面写的内容。

      要发送带有错误的自定义消息,请构造带有消息的Error。这将设置message 属性:

      var jsErr = new Error('Unauthorized');
      

      如上所述,在您的情况下直接设置 gRPC 状态代码可能没有用。但是,作为参考,gRPC 状态码可以通过错误的code 属性设置:

      jsErr.code = grpc.status.PERMISSION_DENIED;
      

      要发送您自己的错误代码或其他信息,请使用元数据:

      var metadata = new grpc.Metadata();
      metadata.set('key1', 'value2');
      metadata.set('key2', 'value2');
      
      jsErr.metadata = metadata;
      

      现在,如果服务器如上构造错误并且客户端输出返回的错误:

      console.log(Object.getOwnPropertyNames(err));
      console.log(err);
      console.log(err.metadata);
      

      那么客户端输出是:

      [ 'stack', 'message', 'code', 'metadata' ]
      { [Error: Unauthorized]
        code: 7,
        metadata: Metadata { _internal_repr: { key1: [Object], key2: [Object] } } }
      Metadata { _internal_repr: { key1: [ 'value2' ], key2: [ 'value2' ] } }
      

      【讨论】:

      • 其实我也问过这个问题:D。我以为会有更多的方法。无论如何,非常感谢您的回答(Y)
      【解决方案3】:

      1.是的 2.也许

      避免通过网络发送特殊对象(如new Error)。发送带有错误属性的简单对象并在另一端查找其值。请参阅http://json.org/ 了解易于传输的数据的概述。

      在Server.js里面试试

      function sayHello(call, callback) {
      
          try {
              var myCustomError = {};
              myCustomError.newStatus = 401;
              myCustomError.newMessage = 'custom unAuthorized error';
              console.log(Object.getOwnPropertyNames(myCustomError ));
              console.log(myCustomError);
              callback(null, {error: myCustomError, message: ""});
      
          } catch(e) {
              callback(e);
          }
      }
      

      Client.js 内部

      client.sayHello({name: user}, function(err, response) {
          var myCustomError= response.error;
          if (myCustomError) {
              console.log(Object.getOwnPropertyNames(myCustomError));
              console.log(myCustomError);
          }
      });
      

      【讨论】:

      • 嗯,我能理解。但我想在第一个参数中发送我的错误,作为错误对象,在您的示例中,您将它传递给 2 Nd 参数,它不是错误对象。
      猜你喜欢
      • 2019-11-12
      • 2019-04-04
      • 1970-01-01
      • 2021-04-16
      • 2017-01-12
      • 2015-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多