grpc-dotnet
grpc-dotnet copied to clipboard
Customizing gRPC URLs?
How strict is the gRPC standard with respect to URLs?
Today we generate URLs that always place them at the root of the web app.
e.g. /Count.Counter/AccumulateCount
Is there flexibility to have them prefixed with a URL segment in a web app?
e.g. /api/Count.Counter/AccumulateCount
If this is allowed then we should provide a way to customize service URLs in the startup experience.
UPDATE 2021/04/21 ✔️
Calling a service in a sub-directory documented here: https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot#calling-grpc-services-hosted-in-a-sub-directory
The way I understand it, URL prefixes don't work well with generated clients (see grpc/grpc/issues/14900).
https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
Some gRPC implementations may allow the Path format shown above to be overridden, but this functionality is strongly discouraged. gRPC does not go out of its way to break users that are using this kind of override, but we do not actively support it, and some functionality (e.g., service config support) will not work when the path is not of the form shown above.
Question related to #43
Will the managed client be generated as well (based on .proto
file)? There doesn't seem to be a way to specify a custom url prefix in the .proto
file .
I could be configuration in the client. You'll already need to specify a base address. A prefix could be part of that, e.g. https://localhost:1111/prefix
Right, but other generated clients might not work well with it.
Let's say I have some .proto
files and and build a Aspnet core server, and then generate my C#/Ruby/Java client with the Grpc core tool. As per https://github.com/grpc/grpc/issues/14900#issuecomment-378071244 the client would set the HTTP2 :path
header based on the default format. The prefix wouldn't be compatible then.
We'll be writing a managed client at some point. If we want to support a prefix then we'd include it in request's :path
My grpc server is hosted by Service Fabric as a guest executable service. The accessing url of this service via the reverse proxy from outside the cluster becomes:
http://servicefabric:19081/GuestExeSample/GrpcHello
In order to using current grpc client to access this service, I have to transfer the url to another port without path through nginx.
server {
listen 9001 http2;
location / {
grpc_pass grpc://servicefabric:19081/GuestExeSample/GrpcHello;
}
}
It's a good idea that a managed client supports a prefix. @JamesNK
I think this should be considered as a core feature on the Grpc library. Day by day many api gateways are supporting Grpc communication on top of them, so mounting the services on a custom path or on a virtual host is trivial. Support for the clients to use default path prefix would be an ideal feature to include in all the libraries built by the Grpc client. I prefer the prefix to be not part of proto
file, rather it should be just a default path prefix in the clients.
I'll voice support for this, at least on the client side. The server side could be handled with a proxy like nginx, but I believe the option should exist in a bare server too for the sake of symmetry.
There should be a URL that clients can connect to as follows:
with grpc.insecure_channel('service-host:service-port/service/path') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
Just as we do not and cannot hard code the host and port in the stub, we should not hard code the base path. Everything under the base path is still fair game for grpc to do with as it wants. The publisher of the service and the users of a service would have to agree on the path, just as they do the host and port. I don't believe it need to be any more complicated than that.
Customizing gRPC Urls would be really great.
Under this issue a described a use case for the need to customize URLs (though maybe a special one).
I would also be interested in this feature.
My use-case is the following: I have a service which has both gRPC and REST endpoints. And I'm using Nginx as a reverse proxy. For the REST (HTTP1) endpoints I'm using the proxy_pass
directive in the nginx.conf
. But that does not work with gRPC, for gRPC I need to use grpc_pass
. So in the nginx.conf
I need to be able to differentiate between the two parts of the service.
If I could host the gRPC endpoints under a subroute (let's say /grpc
), then I'd be able to do this:
http {
server {
listen 80;
location /grpc {
grpc_pass grpc://localhost;
}
location / {
proxy_pass http://localhost;
}
}
}
I'm not sure if I have a way to do this without hosting the gRPC endpoints on a specific subroute.
I would also be interested in this feature.
My use-case is the following: I have a service which has both gRPC and REST endpoints. And I'm using Nginx as a reverse proxy. For the REST (HTTP1) endpoints I'm using the
proxy_pass
directive in thenginx.conf
. But that does not work with gRPC, for gRPC I need to usegrpc_pass
. So in thenginx.conf
I need to be able to differentiate between the two parts of the service.If I could host the gRPC endpoints under a subroute (let's say
/grpc
), then I'd be able to do this:http { server { listen 80; location /grpc { grpc_pass grpc://localhost; } location / { proxy_pass http://localhost; } } }
I'm not sure if I have a way to do this without hosting the gRPC endpoints on a specific subroute.
There is a solution to your problem. The paths to grpc services follow a specific format:
host/package.service/method
Using the package name as a prefix to detect gRPC services has worked well for us so far. You just need to make sure your services are either all in the same package or you add all package names as valid prefixes for grpc_pass
I would also be interested in this feature. My use-case is the following: I have a service which has both gRPC and REST endpoints. And I'm using Nginx as a reverse proxy. For the REST (HTTP1) endpoints I'm using the
proxy_pass
directive in thenginx.conf
. But that does not work with gRPC, for gRPC I need to usegrpc_pass
. So in thenginx.conf
I need to be able to differentiate between the two parts of the service. If I could host the gRPC endpoints under a subroute (let's say/grpc
), then I'd be able to do this:http { server { listen 80; location /grpc { grpc_pass grpc://localhost; } location / { proxy_pass http://localhost; } } }
I'm not sure if I have a way to do this without hosting the gRPC endpoints on a specific subroute.
There is a solution to your problem. The paths to grpc services follow a specific format:
host/package.service/method
Using the package name as a prefix to detect gRPC services has worked well for us so far. You just need to make sure your services are either all in the same package or you add all package names as valid prefixes for grpc_pass
Hi @Blackclaws, what about a Service that is common to multiple components, like the HealthCheck service. In this case the service has the same Name and Package on every deployment, how could we route the client to the correct component? Assuming you have a single host
and many components with services deployed under that host.
Thanks.
Hi @Blackclaws, what about a Service that is common to multiple components, like the HealthCheck service. In this case the service has the same Name and Package on every deployment, how could we route the client to the correct component? Assuming you have a single
host
and many components with services deployed under that host.
In that case the mentioned idea will not work. What you could do is differentiate based on headers. Those are something you can add to calls easily using interceptors. Nginx can proxy pass based on headers.
You do need a way to differentiate the individual health check services anyway, a header can serve that purpose just as well as a prefix. In general I'd like to mention that maybe what you'd want instead is a health aggregation service that individually connects to each individual HealthCheck service and produces an aggregate result that is exposed to the outside, kind of as a Backend for Frontend type of approach.