你可以使用HTTP2请求成功调用gRPC服务吗?

huangapple go评论108阅读模式
英文:

Can you use a HTTP2 request to successfully call a gRPC service?

问题

由于grpc建立在http2之上,您可以使用http请求直接调用grpc服务吗?

例如,如果您使用以下proto启动了一个grpc服务:

option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// 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;
}

然后,发送一个curl请求到本地主机和端口号:

curl --http2 -H "Content-Type: application/grpc+proto" -d '{"name": "test"}' http://localhost:50051/io.grpc.examples.helloworld.Greeter/SayHello

这是否受支持?我收到以下错误:

io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: Unexpected HTTP/1.x request: POST /io.grpc.examples.helloworld.Greeter/SayHello

我不确定我是否调用错误,或者是否不可能这样做。除了使用curl,我还尝试使用Java的HttpClient,但出现了相同的错误。关于这个问题的任何信息都会受到欢迎,谢谢。

英文:

Since grpc is built on top of http2, can you use an http request to directly call a grpc service?

For example, if you start a grpc service with the following proto:

option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// 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;
}

Then send a curl request to that service at localhost and the port number:

curl --http2 -H "Content-Type: application/grpc+proto" -d "{\"name\": \"test\"}" http://localhost:50051/io.grpc.examples.helloworld.Greeter/SayHello

Is this suppported? I get the following error:

io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: Unexpected HTTP/1.x request: POST /io.grpc.examples.helloworld.Greeter/SayHello

I'm not sure if I am making the call incorrectly, or if this isn't possible. Besides using curl, I've also tried using Java's HttpClient, which gave me the same error. Any info on this is appreciated, thanks

答案1

得分: 3

你可以这样做,但你需要遵循gRPC的消息帧格式,它是二进制的。此外,大多数gRPC服务器不支持JSON编码的消息。所以下面是一个protobuf版本的示例:

$ echo -en '\x00\x00\x00\x00\x06\x0a\x04test' | curl --http2-prior-knowledge --header "Content-Type: application/grpc" --header "TE: trailers" --data-binary @- http://localhost:50051/helloworld.Greeter/SayHello | xxd
00000000: 0000 0000 0c0a 0a48 656c 6c6f 2074 6573  .......Hello tes
00000010: 74                                       t

请求的分解如下:

  • \x00\x00\x00\x00\x06。5字节的gRPC帧头。第一个00是一个标志字节,没有设置标志位。最后四个字节是6字节的消息长度。
  • \x0a\x04test。protobuf消息。0a包含字段类型和标签号。04是随后字符串 "test" 的长度。

你可以看到响应也是二进制的gRPC和protobuf,与请求以相同的格式。

你看到的错误通过 --http2-prior-knowledge 修复了。它告诉curl不要使用明文的HTTP/1.1升级到HTTP/2,而是直接开始使用HTTP/2。RFC 9113废弃了HTTP/1.1升级方法,而采用了这种先验知识方法。

英文:

You can, but you need to follow gRPC's message framing format which is binary. Also, most grpc servers don't support JSON-encoded messages. So here's a protobuf version:

$ echo -en '\x00\x00\x00\x00\x06\x0a\x04test' | curl --http2-prior-knowledge --header "Content-Type: application/grpc" --header "TE: trailers" --data-binary @- http://localhost:50051/helloworld.Greeter/SayHello | xxd
00000000: 0000 0000 0c0a 0a48 656c 6c6f 2074 6573  .......Hello tes
00000010: 74                                       t

The request's break-down:

  • \x00\x00\x00\x00\x06. 5 byte gRPC frame header. The first 00 is a flag byte with no flags set. The last four bytes are the message length of 6 bytes.
  • \x0a\x04test. The protobuf message. 0a contains the field type and tag number. The 04 is the length of the following string "test".

You can see how the response was also binary grpc and protobuf in the same format as the request.

The error you were seeing is fixed by --http2-prior-knowledge. It tells curl not to use the plaintext HTTP/1.1 Upgrade to HTTP/2 and instead just start directly with HTTP/2. RFC 9113 deprecated the HTTP/1.1 Upgrade approach for HTTP/2 in favor of this prior knowledge approach.

huangapple
  • 本文由 发表于 2023年8月4日 00:37:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76830055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定