Description
In short, the metadata of my web-grpc client is always empty.
Proto definition
Let's say my proto file looks like:
// some/path/myservice.proto
syntax = "proto3";
import "google/protobuf/empty.proto";
package some.path.myservice;
service MyService {
rpc RespondMetadata(google.protobuf.Empty) returns (google.protobuf.Empty) {}
}
Code generation
I generated code for my proto files using "grpc-web": "^1.4.2"
.
And protoc:
$ protoc --version
libprotoc 24.3
The command is:
protoc -I=. --js_out=import_style=commonjs,binary:. \
--grpc-web_out=import_style=typescript,mode=grpcweb:. \
some/path/myservice.proto
Server-side
The server of this gRPC sets the metadata header some-header
in Golang:
func (s myServer) RespondMetadata(ctx context.Context, request *emptypb.Empty) (*emptypb.Empty, error) {
// ... Do some other stuff
// All side-effects resulting from this call happen sucessfully in the server. e.g. printing to console
// Set the metadata key value pair as header
header := metadata.New(map[string]string{"some-header": "some-value"})
err := grpc.SetHeader(ctx, header)
if err != nil {
return nil, fmt.Errorf("Failed to set header: %w", err)
}
return &emptypb.Empty{}, nil
}
I know this is working fine because I can create a Golang client for this server and successfully read the headers, both by dialing into the grpc port directly, or by dialing an Envoy proxy that I have already set up.
Metadata transformed into HTTP headers
If I create my grpc client for the browser using grpc-web, I can see the metadata present in the HTTP Response Headers of the browser Network tab:

Issue within browser (grpc-web) typescript code
However, in the code the metadata is always empty.
I initialize my client in the following way:
import { MyServiceClient } "some/path/MyServiceClientPb";
const client = new MyServiceClient(serverUrl, null, null)
And I have tried calling the method and reading metadata in the following ways:
const grpcRequest = new google_protobuf_empty_pb.Empty();
const call = client.respondMetadata(grpcRequest, {}, (err, response) => {
if (err) {
console.log("There was an error", err);
} else {
// response is of type google.protobuf.Empty
// So I can't read metadata from here
console.log("Successfull response: ", response)
}
});
call.on('status', (status) => {
console.log("Status metadata: ", status.metadata) // This is empty: {}
console.log("Status!:", status)
});
call.on('metadata', (metadata) => {
console.log("Received metadata: ", metadata); // This is empty: {}
const value = metadata['some-header'];
console.log('The received header is: ', value); // this is undefined
})
Any ideas how can I read response metadata? Or why are these approaches not working?
Activity