grpc / grpc-dart

The Dart language implementation of gRPC.
https://pub.dev/packages/grpc
Apache License 2.0
860 stars 271 forks source link

gRPC-web does not seem to capture the GrpcError status and message correctly #535

Closed tembleking closed 2 years ago

tembleking commented 2 years ago

Using gRPC I am able to receive the GrpcError status and message correctly, like this one:

gRPC Error (code: 9, codeName: FAILED_PRECONDITION, message: empty URL provided, details: [], rawResponse: null, trailers: {x-envoy-upstream-service-time: 0, date: Tue, 14 Dec 2021 20:37:49 GMT, server: envoy})'

But when compiled using gRPC-web, the error received is the following: gRPC Error (code: 2, codeName: UNKNOWN, message: null, details: [], rawResponse: null, trailers: {})

The response, however, contains the response error message (grpc-message) and status (grpc-status) in the HTTP headers, as shown in the browser: image


grpc-dart version from pubspec.lock:

  grpc:
    dependency: "direct main"
    description:
      name: grpc
      url: "https://pub.dartlang.org"
    source: hosted
    version: "3.0.2"

Repro steps

  1. Using a GrpcOrGrpcWebClientChannel, create a gRPC client.
  2. Compile the dart application for the browser, for example, using flutter build web or running it with flutter run -d chrome
  3. Execute an RPC that should fail.
  4. See the GrpcError returned by the .onError() or .catchError() methods.

Expected result: The GrpcError should contain the correct fields assigned from the RPC call failed

Actual result: The GrpcError contains an UNKNOWN state, with a null message and no other information whatsoever about the error

Details

Application built with Flutter+Dart and gRPC-Web. The code snippet that handles the error can be seen here: https://github.com/WebEngineeringGroupI/frontend/blob/f4cee7c93cdea608a78c512f431085bcd92bcfa2/lib/services/grpc_api_client.dart#L38

nvx commented 2 years ago

I ran into this as well. The solution is to add grpc-status and grpc-message to the Access-Control-Expose-Headers CORS header. Normally the status is sent as a trailer if headers have already been sent, but if the headers have not already been sent then it can be sent as a header which requires whitelisting in CORS (along with any other header metadata you want to be able to access).

Trailers are handled by grpc-web in the body so need no special CORS consideration.

Oddly my error was slightly different to yours:

gRPC Error (code: 2, codeName: UNKNOWN, message: HTTP request completed without a status (potential CORS issue), details: null, rawResponse: , trailers: {})

Which despite the explicit mention of CORS I still took longer than I'd like to admit to work out what the problem was.

tembleking commented 2 years ago

Wow @nvx that solved the problem. I just added grpc-status and grpc-message to the Access-Control-Expose-Headers and the error message is correct! Thank you so much! :clap: :clap: :100: