Golang HTTP Request Header 分析

协议

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容