Могу ли я отправить пользовательское сообщение об ошибке с сервера на клиент GRPC?
Я создал простой 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.
Мои вопросы
- Можно ли отправить пользовательское сообщение клиенту?
- Могу ли я создать ошибку GRPC, а не ошибку JavaScript?
- один из способов отправки пользовательских атрибутов клиенту, я думаю, это добавить пользовательские данные в
Metadata
, но я также не уверен, как это сделать.
3 ответа
На этот же вопрос есть полезный ответ в группе Google gRPC: https://groups.google.com/d/msg/grpc-io/X_bUx3T8S7s/x38FU429CgAJ
Вы можете отправить пользовательское сообщение о состоянии клиенту, используя свойство сообщения объекта Error. В вашем примере это "MY_ERROR". Код состояния должен быть в свойстве code, так же, как вы видите его на стороне клиента.
Если вы хотите использовать структуру состояния gRPC вместо ошибки JavaScript, вы можете сделать это, заполнив свойство "code" и свойство "message" или "details" объекта.
Если вы хотите отправить метаданные, вы должны создать экземпляр класса grpc.Metadata, а затем добавить пары ключ / значение в результирующий объект. Затем вы можете передать его в качестве третьего аргумента обратного вызова или установить свойство метаданных ошибки, чтобы отправить его клиенту с ошибкой.
Обратите внимание, что коды состояния, которые использует gRPC, являются не кодами состояния HTTP, а специальными кодами gRPC, которые определены в grpc.status. Вы должны только установить свойство кода ошибки, используя эти коды. Если вы хотите отправить свои собственные коды, используйте вместо этого метаданные.
Я проиллюстрирую то, что написано выше, на нескольких примерах.
Чтобы отправить пользовательское сообщение с ошибкой, создайте 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' ] } }
1. Да 2. Может
Избегайте отправки специальных объектов (например, new Error
) по проводу. Отправьте простой объект со свойством 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);
}
});
Согласно определению
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: {} }
}