如何在 Golang 中获得 request.Header 字节的大小?

How can I get a size of request.Header in bytes in Golang?

我需要找到 request.Header 的大小,其中请求有 *http.Request 类型:

req, err := http.NewRequest("GET", "/", nil)
cookie := &http.Cookie{Name: "foo", Value: "bar"}
req.AddCookie(cookie)

我试过了

len(request.Header) # returned the number of elements in the map -- essentially the number of headers

for k, v := range req.Header {
  bytesSize += len(k) + len(v)
}

这也不起作用,因为 v 是一张地图。

我找到了 个问题,但答案似乎很复杂(它们的映射值是整数,但这里不是这种情况)。

更新:实际上这里是 type Header map[string][]string 的定义,因此我们不必使用递归。

https://pkg.go.dev/net/http#Server.MaxHeaderBytes 可以为您处理。

此演示在 Playground 中无法可靠运行(拨号或连接超时)。不过,它似乎在本地可靠地工作,这让我猜想这是 playground 行为的产物。

我们将以低 MaxHeaderBytes 启动一个 http 服务器,然后大大超过它。

package main

import (
    "context"
    "fmt"
    "io"
    "net"
    "net/http"
    "strings"
    "time"
)

func main() {
    res := make(chan error)
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "%+v", r.Header)
    })
    s := &http.Server{
        Addr:           "127.0.0.1:8103",
        Handler:        mux,
        ReadTimeout:    1 * time.Second,
        WriteTimeout:   1 * time.Second,
        MaxHeaderBytes: 2048,
    }
    if l, err := net.Listen("tcp", "127.0.0.1:8103"); err != nil {
        panic(fmt.Errorf("Couldn't listen: %w", err))
    } else {
        go func() {
            res <- s.Serve(l)
        }()
    }
    client := &http.Client{
        Timeout: 3 * time.Second,
    }
    req, err := http.NewRequest("GET", "http://127.0.0.1:8103", nil)
    if err != nil {
        panic(err)
    }
    req.Header.Add("X-Long-Header", strings.Repeat("long ", 2048)+"header")
    resp, err := client.Do(req)
    if err != nil {
        panic(fmt.Errorf("HTTP Request failed: %w", err))
    }
    fmt.Println(resp)
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(fmt.Errorf("Could not read response body: %w", err))
    }
    fmt.Println("Body:", string(body))
    s.Shutdown(context.Background())
    <-res
}

在这里,我将 MaxHeaderBytes 设置为一个相当小的值。我在 X-Long-Header: long long long .... header 中传递的值远远超过该值。如果您可以让 playground 工作(只需 运行 几次)或 运行 在本地工作,您将获得:

&{431 Request Header Fields Too Large 431 HTTP/1.1 1 1 map[Content-Type:[text/plain; charset=utf-8]] 0xc00001a180 -1 [] true false map[] 0xc000176000 <nil>}
Body: 431 Request Header Fields Too Large

如您所见,如果所有 header 都太大,将自动生成 431。

如果特定的 header 太长,您的处理程序本身用 431 响应可能是合适的,但是当您的处理程序被传递 http.Request 时,header 已收到。尝试自己计算 header 的总长度然后基于此返回 431 是没有意义的。

此外,标准 header 可能来来去去,因此将整体 header 大小限制得太紧是不明智的。

相反,请检查您关心的 header 个人。