gRPC Node Js客户端:“找不到方法” stream_csv.proto client.js server.py

问题描述

我有一个用python实现的gRPC服务器,我正在从NodeJS调用RPC,但它给出了一个错误“找不到方法”。当我使用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.request 从urllib.error导入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,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!'
}

解决方法

我为您的Python(和Golang)服务器实现编写了一个更简单的变体。

两者均可按原样与Node.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 CamelCasing服务,rpc和消息名称的样式指南,并在其他地方使用下划线,请参见Style Guideprotoc编译时,结果并不总是完全匹配(例如Python的CamelCased函数,而不是带有下划线的小写字母)。

按惯例,您的原型应为:

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

...然后Python生成的函数也将是(!)SayHello

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...