-
Notifications
You must be signed in to change notification settings - Fork 765
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
Decoding grpc-status-details-bin ? #399
Comments
Go encodes the metadata as base64 after marshalling the proto message, so you should be able to base64 decode followed by a unmarshalling of the data into a |
See https://github.com/grpc/grpc-go/blob/ca62c6b92c334f52c7e48b7cbf624f3b877fb092/internal/transport/http_util.go#L317 for how its done in Go clients. Should be very applicable to JS clients too. We may need to add some convenience function for this, but for now this is what you will need. |
Thanks for the (very) quick reply. DIdn't recognize a base64 string, but yeah, decoded it this way and it's OK ;) Thanks |
Struggling for a few hours now, I can't figure out how to parse the base64decoded string. If you have any clue ^^ Server side :
Client side, I receive :
|
Yeah that looks right, but you still need to parse the |
You totally lost me there |
OK I thought you had parsed this into a status type already, but I assume this string is just what you go from base64 decoding the trailer then? Here's what you need to do:
That will give you your 3 error details marshalled into JS types. |
Thanks for the help ! Stuck at step 2 :D Tried :
But decoder triggers an error ... "Failure: Decoder hit an error" |
You still need to base64 decode it first. What does |
You should be able to get a |
atob returns a string :/ |
Does creating a |
So, I got it working with a (not-so-pretty) double deserialization (grpc-go can only send
and proto :
Thanks for your help |
Nice work! Just a little clarification - the double marshalling is a consequence of using |
Yep but when using directly |
This is really confusing. A small helper would go long way in clarifying how this works. |
Hello @jscti, what client implementation were you using here? Improbable's or this repository's? We currently use improbable's in most of our clients and were going to give a go at the 'official' one (we've generated our client with typescript support). We use grpc-go in our services and Improbable's excellent proxy implementation (we currently wrap a grpc-go server using their utils) which allows us to embed some internal authentication logic. We can successfully make requests and the proxy seems to be completely compatible with this new client. However, we rely a lot on adding custom error payloads via status.WithDetails, which the grpc-go server implementation writes as the header The problem is that at the moment there is no way to access this header from the API exposed by these clients. We would expect it to be included here, but the client does not even check for the header. What are your thoughts about including this header data as part of the error callback object? We would happily add it and submit a patch. It's not a huge issue for us at the moment, as we still have improbable's clients. But it'd be great to see this client as feature-rich as Improbable's, which allows you to do this. Thanks a lot! |
Hi @jscti , I have similar need with you. We write grpc server in golang and client in angular. We also read the article called "Advanced gRPC Error Usage" written by @johanbrandhorst . Now my question is that I can't get metadata, and our error return only have two fileds, not including response metadata. The code as below. is some code wrong? server side:
} client side: proto file: syntax = "proto3"; package helloworld; service Greeter { message HelloRequest { message HelloReply { What can we do to solve this problem? Looking for your reply. Thank you ! |
@NobodyXiao, it's worth inspecting the message sent from the server over the wire (in your browser network tab) to see if the error is in the client or the server. |
I have the same problem as @NobodyXiao , is there a specific solution now? |
I have the same problem. |
We have the same problem, expected to have I might have time for a PR next week if @jesushernandez hasn't started yet? Otherwise, I might put up a git bounty instead if anyone wants to join? |
Yeah @RXminuS I just crashed into this. Did you start on a PR? Or @jesushernandez ? I would do it myself even but it's vaguely daunting. I guess we'd need something like: const GRPC_STATUS_DETAILS = "grpc-status-details-bin";
// ...
var responseHeaders = self.xhr_.getResponseHeaders();
if (GRPC_STATUS in responseHeaders &&
Number(self.xhr_.getResponseHeader(GRPC_STATUS)) != StatusCode.OK) {
self.onErrorCallback_({
code: Number(self.xhr_.getResponseHeader(GRPC_STATUS)),
message: self.xhr_.getResponseHeader(GRPC_STATUS_MESSAGE),
details: self.xhr_.getResponseHeader(GRPC_STATUS_DETAILS)
});
} So that's simple enough, no? But then let's say I'm attaching DebugInfo from the errdetails package as described by Mr. @johanbrandhorst , well then I confess I wouldn't know what to do next, or how this sort of thing fits into the overall project. EDIT: Little more data in grpc/grpc-node#184 and the node-grpc-error-details package, perhaps? |
I also have the same problem. I can't get metadata on I followed the code to identify the reason for discrepancy and if I understand correctly. At line 129 and line 136 of grpc-web/javascript/net/grpc/web/grpcwebclientreadablestream.js Lines 125 to 135 in c6af7c6
Causing block which is meant to parse http1 headers, and call status callback/promise to skip. grpc-web/javascript/net/grpc/web/grpcwebclientreadablestream.js Lines 141 to 181 in c6af7c6
Reference code used to Test and DebugServer Side:
Client Side:
|
Does the typescript definition for |
I have the same problem. Does anyone know how to decode grpc-status-details-bin header sent by Golang server ? |
For me, the problem came down to the Envoy proxy not passing
|
@twixthehero I have grpc-status-details-bin passed by Envoy. The problem is that I don't have idea how to get it from grpc client. Can you send example ? |
I used @jscti 's example above like so: First, I included google's Once these are compiled, they are used in my Typescript code like so: import { DeleteCharacterResponse } from './character_pb.d';
import * as grpcWeb from 'grpc-web';
import { ErrorDetails } from 'src/proto/error/error_details_pb';
import { Status } from 'src/proto/google/rpc/status_pb';
...
const promise = new Promise<DeleteCharacterResponse>((resolve, reject) => {
const metadata = { Authorization: `Bearer token` };
// this.service is my grpc client
const stream = this.service.deleteCharacter(
request,
metadata,
(err: Error | Status, response: DeleteCharacterResponse): void => {
if (err) {
reject(err);
} else {
resolve(response);
}
}
);
stream.on('data', (response: DeleteCharacterResponse) => {
console.log('deleteCharacter data: ' + JSON.stringify(response));
});
stream.on('status', (status: grpcWeb.Status) => {
console.log('deleteCharacter status: ' + JSON.stringify(status));
const metadata = status.metadata;
if (metadata !== undefined) {
const statusEncoded = metadata['grpc-status-details-bin'];
const statusDecoded = atob(statusEncoded);
const status = Status.deserializeBinary(
this.stringToUint8Array(statusDecoded)
);
const details = status
.getDetailsList()
.map((detail: any) =>
ErrorDetails.deserializeBinary(detail.getValue_asU8())
);
console.log(`details: ${JSON.stringify(details)}`);
}
});
stream.on('end', () => {
console.log('deleteCharacter end');
});
stream.on('error', (err: grpcWeb.Error) => {
console.log('deleteCharacter error: ' + JSON.stringify(err));
});
});
// convert promise to observable and return
const observable = from<Promise<DeleteCharacterResponse>>(promise);
return observable.pipe(...);
...
private stringToUint8Array(str: string): Uint8Array {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0; i < str.length; i++) {
bufView[i] = str.charCodeAt(i);
}
return bufView;
}
syntax = "proto3";
import "google/rpc/error_details.proto";
package error;
message ErrorDetails {
google.rpc.RetryInfo retryInfo = 1;
google.rpc.DebugInfo debugInfo = 2;
google.rpc.QuotaFailure quotaFailure = 3;
google.rpc.PreconditionFailure preconditionFailure = 4;
google.rpc.BadRequest badRequest = 5;
google.rpc.RequestInfo requestInfo = 6;
google.rpc.Help help = 7;
google.rpc.LocalizedMessage localizedMessage = 8;
} |
@twixthehero Thank you very much. It works ! 👍 |
Updated the installation instructions to reflect that we clone from a remote repository on github.
I've created an NPM package to deserialize |
here is snippet to decode Status and ErrorInfo within:
here we decode Status, than get DetailsList, and get Array of it and we have |
Status object thrown by grpc commands contains metadata that needs to be serialized in order to map it to custom errors generated through proto files grpc/grpc-web#399
Status object thrown by grpc commands contains metadata that needs to be serialized in order to map it to custom errors generated through proto files grpc/grpc-web#399
Status object thrown by grpc commands contains metadata that needs to be serialized in order to map it to custom errors generated through proto files grpc/grpc-web#399
Status object thrown by grpc commands contains metadata that needs to be serialized in order to map it to custom errors generated through proto files grpc/grpc-web#399
Hi there
Server side, we send an error withDetails (in GO) :
Client side (js / typescript), we need to retrieve these details somehow but all we receive is a serialized string (
trailers.get('grpc-status-details-bin')
) .. how can we decode it ?Thanks
The text was updated successfully, but these errors were encountered: