前言

今天使用 GoLang 的 http 包发现设置的 Header 大小写与我传入的不一致。

标准

HTTP 的标准规定 HTTP 的 Header 是大小写不敏感的。

GoLang HTTP

GoLang 在设置 Header 时会进行标准化处理,首字母大写,并且 - 之后的第一个字母也是大写的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
func (h Header) Add(key, value string) {
	textproto.MIMEHeader(h).Add(key, value)
}

func (h MIMEHeader) Add(key, value string) {
	key = CanonicalMIMEHeaderKey(key)
	h[key] = append(h[key], value)
}

// CanonicalMIMEHeaderKey returns the canonical format of the
// MIME header key s. The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
// the rest are converted to lowercase. For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
// MIME header keys are assumed to be ASCII only.
// If s contains a space or invalid header field bytes, it is
// returned without modifications.
func CanonicalMIMEHeaderKey(s string) string {
	// Quick check for canonical encoding.
	upper := true
	for i := 0; i < len(s); i++ {
		c := s[i]
		if !validHeaderFieldByte(c) {
			return s
		}
		if upper && 'a' <= c && c <= 'z' {
			s, _ = canonicalMIMEHeaderKey([]byte(s))
			return s
		}
		if !upper && 'A' <= c && c <= 'Z' {
			s, _ = canonicalMIMEHeaderKey([]byte(s))
			return s
		}
		upper = c == '-'
	}
	return s
}

从上面的源码中可以发现会对 key 进行 canonicalMIMEHeaderKey 处理。

Set 也是一样的

1
2
3
4
5
6
7
func (h Header) Set(key, value string) {
	textproto.MIMEHeader(h).Set(key, value)
}

func (h MIMEHeader) Set(key, value string) {
	h[CanonicalMIMEHeaderKey(key)] = []string{value}
}

不进行大小写转换

如果不想自动进行大小写转换,问了下 DeepSeek 可以直接设置 Header

1
req.Header["key"] = []string{"value"}