3

I wrote a test gRPC server in Python and client on ReactJS (ES6). It's simple python gRPC server which provides authentication methods for client. Also configured EnvoyProxy for transporting HTTP requests into HTTP2. When I call gRPC method from my client I get {"code": 12, "message": "Method not found"}.

In status codes docs this error described as not implemented method:

grpc status code docs

but I'm sure that method is implemented!

Here is some of my Python service code:

class AuthenticationServicer(glyphs_pb2_grpc.AuthenticationServicer):

    def SignIn(self, request, context):

        # do authentication method stuff...

        return glyphs_pb2.TokenResponse(
            success=True,
            response=glyphs_pb2.Token(token=refresh_token.token, expired_at=str(refresh_token.expired_at)),
        )

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

glyphs_pb2_grpc.add_AuthenticationServicer_to_server(AuthenticationServicer(), server)

print('Starting server. Listening on port 50051.')

server.add_insecure_port('localhost:50051')
server.start()

I tried calling the gRPC methods from python client and it works as expected:

# client.py
channel = grpc.insecure_channel('localhost:50051')
stub = glyphs_pb2_grpc.AuthenticationStub(channel)

sign_in_form = glyphs_pb2.SignInForm(email="admin@localhost", password="123456a")
sign_in_response = stub.SignIn(sign_in_form)

print("Refresh Token: ")
print(sign_in_response)
~$ python ./client.py
Refresh Token: 
success: true
response {
  token: "7ae52622cf556632de0a0fe115e1fc0c5adaea9c"
  expired_at: "2019-11-13 13:22:56.870937"
}

My envoy YAML configuration:

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 9090 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  cluster: authentication_service
                  max_grpc_timeout: 0s
              cors:
                allow_origin:
                - "*"
                allow_methods: GET, PUT, DELETE, POST, OPTIONS
                allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
                max_age: "1728000"
                expose_headers: grpc-status,grpc-message
          http_filters:
          - name: envoy.grpc_web
          - name: envoy.cors
          - name: envoy.router
  clusters:
  - name: authentication_service
    connect_timeout: 0.25s
    type: logical_dns
    http2_protocol_options: {}
    lb_policy: round_robin
    hosts: [{ socket_address: { address: host.docker.internal, port_value: 50051 }}]

ReactJS client code:

const { AuthenticationClient } = require('./glyphs_grpc_web_pb');
const { SignInForm } = require('./glyphs_pb');


let client = new AuthenticationClient('http://localhost:9090/', null, null);

let form = new SignInForm();
form.setEmail('admin@localhost');
form.setPassword('123456a');

client.signIn(form, {}, (err, res) => {
    if (res) {
        console.log(res);
    } else {
        console.log(err);
    }
});

I expected the output to be my token response, but the actual output was:

grpc-web client response

Package.json:

{
  "name": "glyphs"
  "dependencies": {
    "google-protobuf": "^3.10.0",
    "grpc-web": "^1.0.6",
    "react": "^16.10.2",
    "react-dom": "^16.10.2",
    "react-scripts": "3.2.0"
  }
}
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60

2 Answers2

2

I experienced a similar method not found error, fixed by changing client creation to

let client = new AuthenticationClient('http://localhost:9090', null, null);

Note: remove the / at the end.

And in this way the call client.signIn(...) will be directed to

http://127.0.0.1:9090/[package-if-defined-in-proto].AuthenticationServicer/SignIn

But if

let client = new AuthenticationClient('http://localhost:9090/', null, null);

Then the same call client.signIn(...) will be directed to

http://127.0.0.1:9090//[package-if-defined-in-proto].AuthenticationServicer/SignIn

And the double // is causing the method not found issue. I suppose grpc-web is automatically and enforcedly adding a / to the hostname.

y g
  • 49
  • 1
  • 7
0

I had this problem and I had forgotten to register my service to server

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
glyphs_pb2_grpc.add_AuthenticationServicer_to_server(AuthenticationServicer(), server)

this is how I solve it

  • While this may answer the question, it would be a better answer if you could provide some explanation about **why** it does so. – Ben A. Sep 01 '23 at 23:05