首页 > 解决方案 > 如何在 Golang 中获取 request.Header 的大小(以字节为单位)?

问题描述

我需要找到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所以我们不必使用递归。

标签: gorecursive-datastructures

解决方案


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 响应是没有意义的。

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

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


推荐阅读