4

I am trying to call a gRPC service from Angular application.

If I host the server locally and call it from Anuglar application then it works.

    const client = new HelloWorldServiceClient("http://localhost:5001");
          
    const request = new SayHelloMessage();
    request.setName("User");
    
    client.sayHelloWorld(request, (err: any, response: any) => {
            
    if (err) {
         console.log(err);
         this.response = err;
         return;
    }
    this.response = response.getMessage();
  });

However, when I try to call a gRPC service hosted on a remote server it throws "Response closed without headers" error.

Changed code:

const client = new HelloWorldServiceClient("http://server_name:5001");

If I try to call the same service hosted on a server using NodeJS client then it works too.

NodeJS Code:

var url = "server_name_with_out_http:5001"; // e.g. server_name:5001 and not http://server_name:5001

const client = new HelloWorldServiceClient( 
    url,
    grpc.credentials.createInsecure()
);

var req = { name: "User" };

client.sayHelloWorld(req, (error, reply) => {
    if (!error) {
        console.log(reply.message);
    } else {
        console.log(error);
    }
});

What could be the reason why Angular application is not able to call gRPC service hosted on the server?

Chrome dev tool logs:

enter image description here

enter image description here

enter image description here

developer
  • 1,401
  • 4
  • 28
  • 73
  • 1
    It seems likely that the issue is with the "gRPC service hosted on a remote server"; showing your working "NodeJS client" code might help (i.e. is that using gRPC or gRPC-Web). Tools like [bloomRPC](https://github.com/bloomrpc/bloomrpc)/[kreya](https://kreya.app/) provide an alternative way to confirm the service is working. – Brits Feb 19 '22 at 01:38
  • 1
    Thanks @Brits for looking into this. I have updated the question with NodeJS working code. – developer Feb 21 '22 at 09:52
  • 1
    Your question is still a bit low on detail. It sounds like you are running an angular app in the browser; that being the case you need to use [grpc-web](https://github.com/grpc/grpc-web) but no mention is made of this (e.g. envoy proxy etc; note that a grpc-web client cannot connect directly to a grpc server). However you say that it works locally which is confusing (so my assumption may be wrong). [This article](https://grpc.io/blog/state-of-grpc-web/) might help (it's a bit old now but provides a good summary). – Brits Feb 21 '22 at 18:24
  • 1
    Thanks for your comments. Just to make it clearer, yes, I am running an angular application in the browser. The angular application needs to consume a grpc service created using .Net core. I believe it is using grpc-web. If I run the grpc service on localhost then Angular application is able to consume it. However, if I deploy the grpc service on a server then Angular application is not able to consume it. The nodejs application is able to consume both locahost and server based grpc service. – developer Feb 21 '22 at 22:20
  • 1
    Thanks for clarifying (and, yes, .net-core does have the ability to serve grpc-web services directly). Please open your web browser dev tools network tab and then open your web app. Do you see any failed requests there (or anything logged to the console); if so please post the details (unfortunately there are a number of possible issues when accessing from a browser e.g. CORS). – Brits Feb 21 '22 at 23:33
  • @Brits - Dev tool shows error in the network tab but not much information to know what could be the issue. I have still attached screenshots on the question. It might be due to CORS but not sure how to fix it. – developer Feb 22 '22 at 15:49
  • Ok so it looks like you are running the webapp locally and attempting to connect to a remote grpc-web server (providing enough information to allow the issue to be duplicated would make this easier) meaning CORS will be an issue. [This article](https://learn.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-6.0#grpc-web-and-cors) explains how to work with CORS. – Brits Feb 22 '22 at 18:43
  • Thanks @Brits, I will check the CORS article. would NodeJS app have an issue if there is a problem of CORS from the server side? – developer Feb 23 '22 at 09:47
  • CORS is a security measure in web browsers (see [this description](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)) and not generally applicable to calls made from applications not running in a browser (it would not have a benefit because the application can control HTTP headers; something the browser does not allow). Note that it may be possible to disable this in the browser for testing purposes (see the comments under [this answer](https://stackoverflow.com/a/3177718/11810946)). – Brits Feb 23 '22 at 18:28
  • Thanks, very useful information for me, I will have further look into it. – developer Feb 24 '22 at 13:20

2 Answers2

4

This is most likely caused by the common CORS Browser restrictions, and not exactly by angular. This question contains great guidance on CORS.

Calling HTTP services from a Node app (or from postman) will not enforce CORS, while calling it from a market standard browser certainly would.

I know there is far more to it than my next simplified comments but this should give you a starting point (a deeper dive is in the links I shared above)

For browsers to execute XMLHttpRequest's from one website to other domains (or other ports of the same domain):

  1. the browser will send an OPTIONS HTTP request before every real request to the other domain and only allow the actual request when the OPTIONS response headers authorize it.
  2. the "other" website must be configure to reply to OPTIONS requests with specific Headers (Access-Control-Allow-Origin, Access-Control-Request-* ...).

==> If the other server does not reply to OPTIONS requests or does not provide the appropriate headers in the OPTIONS response, you can get a range of different errors, and "Response closed without headers" is one of them.

I believe your gRPC web application is not configured with the proper CORS to authorize communications from the website where you are hosting your angular application (even if it is localhost, you would still need to configure it).

This article has practical guidance on how to configure CORS on .netcore applications

and finally, This github issue / responses contains some more info about a similar error some people faced with gRPC, you might have stepped into the same one. If you have already configured your CORS rules.

Clément Jean
  • 1,735
  • 1
  • 14
  • 32
The Fabio
  • 5,369
  • 1
  • 25
  • 55
1

I would recommend to not directly call you backend from your browser client (if that's not want you are doing, let me know) and use a reverse proxy instead. There are many tools out there to do that:

In fact the examples in gRPC's Github repository use envoy (check here) and one of the mail in the grpc-io mail list mentions that directly contacting your backend with your gRPC web frontend is not recommended.

Clément Jean
  • 1,735
  • 1
  • 14
  • 32