協(xié)議
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 必須要是編碼為小寫。
問題
其實這章節(jié)的疑惑點是請求頭在進(jìn)入到 Go 服務(wù)端后,大小寫會被轉(zhuǎn)換。例如: aB-cDE -> Ab-Cde 為啥會做類似如此奇怪的轉(zhuǎn)換。
實現(xiàn)
直接看 Go 的處理。主邏輯函數(shù)在: go/src/net/textproto/reader.go:canonicalMIMEHeaderKey
主要的調(diào)用路徑為:
serve->readRequest->readRequest->ReadMIMEHeader
emmm, 自己看代碼理解。來測試一下,拷貝一下代碼運行
func main() {
fmt.Println(canonicalMIMEHeaderKey([]byte("aB-cDE")))
}
//輸出:Ab-Cde
總結(jié)
了解這個有啥用呢?嗯,可以這樣,然后那樣...
漏點
貌似忘了 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
}
運行結(jié)果
服務(wù)端的輸出:
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
嗯,確實符合協(xié)議標(biāo)準(zhǔn)....
但是
獲取 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]
}
好像也沒啥注意的,客戶端會幫你處理這些小細(xì)節(jié)...
gRPC metadata 的處理大邏輯在 google.golang.org/grpc@v1.36.0/internal/transport/http2_client.go:createHeaderFields