Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactNative GrpcWebFetchTransport produces RpcError: premature end of response #67

Closed
kgoguevgoget opened this issue Jan 20, 2021 · 5 comments

Comments

@kgoguevgoget
Copy link

Hi I am building an android app using React Native and wish to use your library to help with making gRPC requests to my gRPC server, I have managed to successfully get it working without problems using GrpcWebFetchTransport on a pure react application.

But the same code appears to have issues when running on Android using React Native.

I imagine that it has something to do with the Transport I'm using while running on android because I can clearly see that my request is getting sent to the server and processed correctly but the issue lies in the react native side, specifically trying to read the response.

For reference I have tried the other transports you listed in the manual but GrpcWebFetchTransport was the only one that managed to make a request, it just happened to fail on reading the response.

RpcError: premature end of response
    at Object.readGrpcWebResponseHeader (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:152282:38)
    at runtime_rpc_1.UnaryCall._b (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:152106:58)
    at tryCallOne (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:27058:14)
    at http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:27159:17
    at http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:30710:21
    at _callTimer (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:30598:9)
    at _callImmediatesPass (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:30637:7)
    at MessageQueue.callImmediates [as _immediatesCallback] (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:30854:14)
    at MessageQueue.__callImmediates (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2738:16)
    at http://localhost:8081/index.bundle?platform=android&dev=true&minify=false:2524:18

Note: that my gRPC server only accepts binary requests and only unary calls.

example proto

syntax = "proto3";

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Client code

import {GrpcWebFetchTransport} from "@protobuf-ts/grpcweb-transport";
let transport = new GrpcWebFetchTransport({
    format: "binary",
    baseUrl: "http://localhost:50051",
  });
 let client = new GreeterClient(transport);
 let {response} = await client.sayHello({ name: "test" });
console.log("grpcResponse:  " + response)
}

I have been able to successfully make a gRPC request using https://github.com/improbable-eng/grpc-web/tree/master/client/grpc-web-react-native-transport but this requires me to generate the proto file using a completely diffrent method and moving away from your library which I don't want to do.

Using the Improbable-end/grpc-web-react-native transport. It seems to be using XHR but im not sure if thats the reason that one works and your GrpcWebFetch doesn't.

Any ideas?

@kgoguevgoget kgoguevgoget changed the title ReactNative grpcwebtransport produces RpcError: premature end of response ReactNative GrpcWebFetchTransport produces RpcError: premature end of response Jan 20, 2021
@timostamm
Copy link
Owner

timostamm commented Jan 20, 2021

Hey @kgoguevgoget,

the RpcError seems to originate here:

if (!fetchResponse.body)
throw new RpcError('premature end of response', GrpcStatusCode[GrpcStatusCode.DATA_LOSS]);

So the body property of the fetch response is null. It should be a ReadableStream<Uint8Array>, see MDN.

We need the ReadableStream for server streaming methods. We cannot just read the entire data using arrayBuffer() (see MDN), because then the client would only know about a response message when the entire response has been read.

The question is, why is body === null?

Apparently, react native uses the fetch API polyfill whatwg-fetch. See setUpXHR.js and fetch.js.

Unfortunately, this polyfill does not implement the body property, see JakeChampion/fetch#746

@timostamm
Copy link
Owner

(sorry, my fat fingers hit enter by accident)

I see the following options:

  1. determine whether the fetch polyfill added by react native is actually necessary, try to turn it off
  2. implement a GrpcWebXhrTransport that uses a similar hack like grpc-web-react-native-transport

Could you have a look at option 1?

I guess this could look like this:

if (__DEV__) {
	(globalThis as any).fetch = (globalThis as any).originalFetch;
}

See https://medium.com/@kureevalexey/hi-birkir-gudjonsson-fb6299cd7e33 and https://github.com/facebook/react-native/blob/6e6443afd04a847ef23fb6254a84e48c70b45896/Libraries/Utilities/PolyfillFunctions.js

@kgoguevgoget
Copy link
Author

Ah Ok I will try to see if option 1 is a viable solution here.

As for option 2, I am afraid that my knowledge in typescript is not as adept as Go so I wouldn't be able to help out with that one but lets see if at least option 1 gets us further

Thanks for the quick response!

@kgoguevgoget
Copy link
Author

kgoguevgoget commented Jan 21, 2021

Hi there, just wanted to give an update and a bit of a guide on how I managed to get it to work:

As per your notes: React Native uses whatwg-fetch which DOES NOT support ReadableStream and the Body property. There is however the following: https://www.npmjs.com/package/react-native-polyfill-globals

From the react-native-pollyfill globals package we can actually patch the whatwg-fetch to support the body and FileReader.readAsArrayBuffer.

npm i @stardazed/streams-polyfill
npm install react-native-polyfill-globals
npm install -D patch-package
npx patch-package --patch-dir node_modules/react-native-polyfill-globals/patches

In index.js at the top add

import "@stardazed/streams-polyfill";

Once ReactNative is patched to support those mentioned above we can actually just run the GrpcWebFetchTransport as I did in the first post.

So yes actually React Native works with your library but you'll need to polyfill + use the patches in the linked package

@timostamm
Copy link
Owner

That's great news, thanks for the info. I have added a note in the manual with a link to this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants