调用gRPC客户端ListRequest时提示方法未找到的问题求助
gRPC方法未找到(StatusCode.UNIMPLEMENTED)问题排查与解决
错误信息
grpc._channel._MultiThreadedRendezvous: <_MultiThreadedRendezvous of RPC that terminated with: status = StatusCode.UNIMPLEMENTED details = "Method not found!" debug_error_string = "UNKNOWN:Error received from peer {created_time:"2023-05-17T02:07:09.472090526+00:00", grpc_status:12, grpc_message:"Method not found!"}" >
相关代码
views.py
@csrf_exempt def add_question(request): if request.method == "POST": data = json.loads(request.body) survey_response_data = { 'id' : 'success' } response = {"errorCode": "", "message": "success", "data": survey_response_data} return JsonResponse(data=response, status=status.HTTP_200_OK) if request.method == 'GET': try: client_stub = create_new_survey_question_client() survey_question = client_stub.List(survey_question_pb2.SurveyQuestionListRequest()) serializer = SurveyQuestionBffSerializer(survey_question, many=True) language_data = [msg for msg in serializer.data] return JsonResponse(data=language_data, status=status.HTTP_200_OK, safe=False) except Exception as E: data = {"message": f"Exception: {E}"} return JsonResponse(data=data, status=status.HTTP_400_BAD_REQUEST, safe=False)
.proto文件
syntax = "proto3"; package survey_question; import "google/protobuf/empty.proto"; service SurveyQuestionController { rpc List(SurveyQuestionListRequest) returns (stream SurveyQuestion) {} rpc Create(SurveyQuestion) returns (SurveyQuestion) {} rpc Retrieve(SurveyQuestionRetrieveRequest) returns (SurveyQuestion) {} rpc Update(SurveyQuestion) returns (SurveyQuestion) {} rpc Destroy(SurveyQuestion) returns (google.protobuf.Empty) {} } message SurveyQuestion { int32 id = 1; string survey = 2; int32 question_no = 3; int32 question_type = 4; int32 order = 5; int32 is_required = 6; } message SurveyQuestionListRequest { } message SurveyQuestionRetrieveRequest { int32 id = 1; }
生成的survey_question_pb2_grpc.py中List方法代码
class SurveyQuestionController(object): """Missing associated documentation comment in .proto file.""" @staticmethod def List(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None): return grpc.experimental.unary_stream(request, target, '/survey_question.SurveyQuestionController/List', survey__question__pb2.SurveyQuestionListRequest.SerializeToString, survey__question__pb2.SurveyQuestion.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
当前环境依赖版本
Django==4.0.7 djangogrpcframework==0.2.1 djangorestframework==3.14.0 exceptiongroup==1.1.1 flake8==6.0.0 futures==3.0.5 google==3.0.0 grpc-django==1.0.0 grpcio==1.54.0 grpcio-reflection==1.54.0 grpcio-testing==1.54.0 grpcio-tools==1.48.1 protobuf==4.22.3
已尝试操作
重新创建proto文件、调整依赖版本,错误依旧。
解决方案
1. 检查服务端方法实现与注册
- 确认服务端已正确实现
SurveyQuestionController服务的List方法,且在启动gRPC服务时完成服务注册(比如在Django gRPC框架中,需确保服务类继承对应基类,并在urls.py中注册)。 - 验证服务端暴露的方法路径与客户端调用路径一致:客户端调用路径为
/survey_question.SurveyQuestionController/List,服务端必须注册完全相同的路径。
2. 修正客户端Stub创建方式
- 检查
create_new_survey_question_client()函数实现,建议使用Stub类而非静态方法调用,避免路径或参数错误:import grpc import survey_question_pb2 import survey_question_pb2_grpc def create_new_survey_question_client(): channel = grpc.insecure_channel('你的服务端地址:端口') return survey_question_pb2_grpc.SurveyQuestionControllerStub(channel)
3. 统一依赖版本
当前grpcio(1.54.0)与grpcio-tools(1.48.1)版本不一致,可能导致生成代码与运行时不兼容。推荐统一版本:
grpcio==1.54.0 grpcio-tools==1.54.0 protobuf==4.21.12 # 该版本与grpcio 1.54.0兼容性更稳定
4. 验证服务端方法可用性
使用grpcurl工具测试服务端方法是否存在:
grpcurl -plaintext 服务端地址:端口 list survey_question.SurveyQuestionController
若返回结果不含List,说明服务端未正确注册该方法;若正常返回,则问题出在客户端调用逻辑。
内容的提问来源于stack exchange,提问作者Saran Prasad
相关产品推荐
相关产品推荐

