Клиент Js узла gRPC: «Метод не найден»

#python #node.js #grpc #grpc-python #grpc-node

#python #node.js #grpc #grpc-python #grpc-узел

Вопрос:

У меня есть сервер gRPC, реализованный на python, и я вызываю RPC из NodeJS, но он выдает ошибку «Метод не найден». Когда я вызываю с помощью клиента python, запрос выполняется успешно.

stream_csv.proto

 syntax = "proto3";

package csv;

service Stream {
  rpc csvToObject(CSVDataRequest) returns (stream CSVDataResponse) {};
  rpc sayHello(HelloRequest) returns (HelloReply);
}

message CSVDataRequest{
  string url = 1;
  enum Protocol {
    HTTP = 0;
    HTTPS = 1;
    FTP = 2;
    SFTP = 3;

}

  Protocol protocol = 2;
}

message CSVDataResponse{
  repeated string row = 1;
}

message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}
  

client.js

 var PROTO_PATH = '../stream_csv.proto';

var grpc = require('grpc');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
    PROTO_PATH,
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
var proto = grpc.loadPackageDefinition(packageDefinition).csv;

function main() {
  var client = new proto.Stream('localhost:5000',
                                       grpc.credentials.createInsecure());
  var user;
  if (process.argv.length >= 3) {
    user = process.argv[2];
  } else {
    user = 'world';
  }
  console.log(user);
  client.sayHello({name: user}, function(err, response) {
    console.log(err);
  });
}

main();
  

server.py

импорт grpc импорт stream_csv_pb2 импорт urllib.запрос из urllib.ошибка импорт HTTPError, URLError из параллельных фьючерсов импорта

 class DataService:

    def csv_to_object(self, request, context):
        url = request.url
        protocol = stream_csv_pb2.CSVDataRequest.Protocol.Name(
            request.protocol)
        fetch_url = protocol.lower()   "://" url

        try:
            with urllib.request.urlopen(fetch_url) as data:
                for line in data:
                    decoded_line = line.decode()
                    val = decoded_line.split(',')
                    print(val)
                    print("Data send")
                    yield stream_csv_pb2.CSVDataResponse(row=val)

            print("Sending finished!")

        except URLError as e:
            context.abort(grpc.StatusCode.UNKNOWN,
                        'Randomly injected failure.')
            # return stream_csv_pb2.CSVDataResponse(row=[], error=e.reason)

    def SayHello(self, request, context):
        name = request.name
        print(name)
        return stream_csv_pb2.HelloReply(message='Hello %s' % (name))

def add_DataServicer_to_server(servicer, server):
    rpc_method_handlers = {
        'CSVToObject': grpc.unary_stream_rpc_method_handler(
            servicer.csv_to_object,
            request_deserializer=stream_csv_pb2.CSVDataRequest.FromString,
            response_serializer=stream_csv_pb2.CSVDataResponse.SerializeToString,
        ),
        'SayHello': grpc.unary_unary_rpc_method_handler(
            servicer.SayHello,
            request_deserializer=stream_csv_pb2.HelloRequest.FromString,
            response_serializer=stream_csv_pb2.HelloReply.SerializeToString,
        )
    }
    generic_handler = grpc.method_handlers_generic_handler(
        'stream_csv.Stream', rpc_method_handlers)
    server.add_generic_rpc_handlers((generic_handler,))


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    add_DataServicer_to_server(DataService(), server)
    server.add_insecure_port('[::]:5000')
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    serve()
  

Ошибка

 Error: 12 UNIMPLEMENTED: Method not found!
    at Object.exports.createStatusError (/home/shantam/Documents/grepsr/client/node_modules/grpc/src/common.js:91:15)
    at Object.onReceiveStatus (/home/shantam/Documents/grepsr/client/node_modules/grpc/src/client_interceptors.js:1209:28)
    at InterceptingListener._callNext (/home/shantam/Documents/grepsr/client/node_modules/grpc/src/client_interceptors.js:568:42)
    at InterceptingListener.onReceiveStatus (/home/shantam/Documents/grepsr/client/node_modules/grpc/src/client_interceptors.js:618:8)
    at callback (/home/shantam/Documents/grepsr/client/node_modules/grpc/src/client_interceptors.js:847:24) {
  code: 12,
  metadata: Metadata { _internal_repr: {}, flags: 0 },
  details: 'Method not found!'
}
  

Комментарии:

1. Вы решили это? Если нет, я посмотрю позже сегодня

2. @DazWilkin да, я решил эту проблему. Я неправильно скомпилировал файл .proto.

3. Полезно знать! Кстати, вы можете переключиться на @grpc/grpc-js . Ваш код работает с подкачкой.

Ответ №1:

Я написал более простой вариант ваших реализаций сервера Python (и Golang).

Оба работают с вашим узлом.JS-клиент как есть.

Я думаю, возможно, ваша проблема так же проста, как необходимость назвать rpc sayHello (а не SayHello ).

 from concurrent import futures
import logging

import grpc

import stream_csv_pb2
import stream_csv_pb2_grpc


class Stream(stream_csv_pb2_grpc.StreamServicer):

    def sayHello(self, request, context):
        logging.info("[sayHello]")
        return stream_csv_pb2.HelloReply(message='Hello, %s!' % request.name)


def serve():
    logging.info("[serve]")
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    stream_csv_pb2_grpc.add_StreamServicer_to_server(Stream(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    logging.basicConfig()
    serve()
  

И:

 node client.js
Greeting: Hello, Freddie!
null
  

Обычно (!) gRPC следует руководству по стилю Protobufs для службы обработки запросов, имен rpc и сообщений и использует подчеркивания в другом месте, см. Руководство по стилю. При protoc компиляции результаты не всегда совпадают идеально (например, функции Python в формате camelCased, а не в нижнем регистре с подчеркиванием).

Обычно ваш прототип будет:

 service Stream {
  rpc CsvToObject(CSVDataRequest) returns (stream CSVDataResponse) {};
  rpc SayHello(HelloRequest) returns (HelloReply);
}
  

… и тогда сгенерированная Python функция тоже будет (!) SayHello .

Комментарии:

1. Проблема заключалась в том, что я неправильно скомпилировал файл ‘.proto’.

2. Я думаю, возможно, ваша проблема так же проста, как необходимость назвать rpc sayHello (а не sayHello). Это сработало для меня