【问题标题】:How can I get a size of request.Header in bytes in Golang?如何在 Golang 中获取 request.Header 的大小(以字节为单位)?
【发布时间】:2021-10-26 22:59:45
【问题描述】:

我需要找到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 是一张地图。

我找到了Computing the memory footprint (or byte length) of a map 的问题,但答案似乎很复杂(它们的映射值是整数,这里不是这种情况)。

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

【问题讨论】:

  • 我很好奇您为什么需要计算地图的大小(以字节为单位)。如果有的话,该大小将取决于实现,并且您的代码可能不会很便携。
  • 您可以使用Header.Write 将其写入缓冲区并查看它有多大。但是你为什么需要它呢?

标签: go recursive-datastructures


【解决方案1】:

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

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

我们将启动一个具有较低 MaxHeaderBytes 的 http Server,然后大大超过它。

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

如您所见,如果所有标题都太大,则会自动生成431。

如果特定标头太长,您的处理程序本身可能会以 431 进行响应,但是当您的处理程序已传递 http.Request 时,标头已被接收。尝试自己计算标头的总长度然后基于此响应 431 是没有意义的。

此外,标准标题可能会来来去去,因此过于严格地限制整体标题大小是不明智的。

相反,请检查您关心的任何单个标题。

【讨论】:

    猜你喜欢
    • 2013-02-01
    • 2013-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多