协议
https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2
Just as in HTTP/1.x, header field names are strings of ASCII characters that are compared in a case-insensitive fashion. However, header field names MUST be converted to lowercase prior to their encoding in HTTP/2. A request or response containing uppercase header field names MUST be treated as malformed.
大体就是:1.X版本 header 是大小写不敏感的,2版本的 header 必须要是编码为小写。
问题
其实这章节的疑惑点是请求头在进入到 Go
服务端后,大小写会被转换。例如: aB-cDE
-> Ab-Cde
为啥会做类似如此奇怪的转换。
实现
直接看 Go
的处理。主逻辑函数在: go/src/net/textproto/reader.go:canonicalMIMEHeaderKey
主要的调用路径为:
serve->readRequest->readRequest->ReadMIMEHeader
emmm, 自己看代码理解。来测试一下,拷贝一下代码运行
func main() {
fmt.Println(canonicalMIMEHeaderKey([]byte("aB-cDE")))
}
//输出:Ab-Cde
总结
了解这个有啥用呢?嗯,可以这样,然后那样...
漏点
貌似忘了 RPC
之间的 metadata
传递。context 之间的传递大小写问题。
Client
func main() {
conn, err := grpc.Dial("localhost:8069", grpc.WithInsecure())
if err != nil {
log.Fatalf("connect error %s", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx := context.Background()
ctx = metadata.AppendToOutgoingContext(ctx, "X-A-bC-De", "ok")
reply, err := c.SayHi(ctx, &pb.GreetRequest{Name: "CTMD"})
if err != nil {
log.Fatalf("say hi error %s", err)
}
log.Printf("greet %v", reply)
}
Server
func (*server) SayHi(ctx context.Context, in *pb.GreetRequest) (*pb.GreetResponse, error) {
md, ok := metadata.FromIncomingContext(ctx)
fmt.Printf("got ctx %#v %t", md, ok)
return &pb.GreetResponse{Message: "Hi " + in.Name}, nil
}
运行结果
服务端的输出:
got ctx metadata.MD{":authority":[]string{"localhost:8069"}, "content-type":[]string{"application/grpc"}, "user-agent":[]string{"grpc-go/1.36.0"}, "x-a-bc-de":[]string{"ok"}} true
嗯,确实符合协议标准....
但是
获取 header/meatadata
有啥注意的呢?
// go/src/net/http/header.go
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
// google.golang.org/grpc@v1.36.0/metadata/metadata.go
func (md MD) Get(k string) []string {
k = strings.ToLower(k)
return md[k]
}
好像也没啥注意的,客户端会帮你处理这些小细节...
gRPC metadata
的处理大逻辑在 google.golang.org/grpc@v1.36.0/internal/transport/http2_client.go:createHeaderFields
网友评论