Golang 操作 HTTP Header 的一个小细节
在平时开发中发送 HTTP 请求是非常频繁的操作,对于 HTTP Header 的操作也是很常用的操作。今天在 Review 一段代码的时候,发现了一个小问题,事后想想其实是很小的问题,很可能都不会影响运行结果,但是都是如果没有遇到过很可能就不会注意到的一些问题,所以作为复盘记录,把这些小细节整理出来。
Header.Add 还是 Header.Set ?
这个问题起始于一段代码(仅保留相关部分):
1 | http.HandleFunc("/forum/correlation", RegForumCorrelation) |
在这里,我看到这个开发者使用了 Header.Add 来设置请求的 Header,我询问开发者这里为什么用 Add 而不用 Set,得到的回答是这两个方法得到的结果是一样的。那么,这里使用 Add 方法对么,或者说合适么?
如果说从结果来看,这里并不会有什么问题,因为这里只是一次性的设置,然后发送请求,目前的实现方法完全可以达到目的而且不会有问题。那么是否就意味着 Header.Add 和 Header.Set 没有什么区别呢,当然不是。所以这里我们本着要想彻底解决问题就要从源码探究的原则来看下这个问题。
其实源码中的注释已经介绍的很明显了,这里不再赘述,我们主要看代码。
1 | type MIMEHeader map[string][]string |
上面就是 Add 和 Set 两个方法的源码,一目了然。Header 是一个 key 为 string,value 为 []string 的 map 类型。其中 key 为 Header 的名称,value 为 Header 对应名称的值,是一个数组。到这里 Add 和 Set 的区别就显而易见了,Add 向 value 的数组中追加一个值,Set 则重写这个值,覆盖掉已有的。
然而这里其实还有个小细节,就是 Header.Get 方法,既然 Header 中 key 对应的 value 是一个 []string 类型,那么 Get 方法获取到的也是这个么?其实并不是:
1 | func (h MIMEHeader) Get(key string) string { |
通过源码可以看到,使用 Get 方法只能够获取到切片中的第一个值,如果想要获取其他的值,只能通过直接访问 Header 的 map 结构去获取了。当然这些也已经在 Get 方法的注释中提到了。所以这里也可以提一个习惯,使用标准库的时候,最好能够详细看看方法的注释,毕竟官方的注释还是很详细的。
在大多数 Get 可以满足需求的时候,我们还是更推荐使用 Get 方法。在源码中有一个登场率很高的函数 CanonicalMIMEHeaderKey,Header 名称在 Add,Set,Get 的时候都会经过这个函数,不知道大家有没有注意过,我们在通过 Add,Set 设置 Header 的时候,Header 的名称都是大小写不敏感的,而在我们接收到的 Header 中却都是规范的。其实这就是 CanonicalMIMEHeaderKey 的作用,把传入的字符串类型参数的首字母大写,然后其他连接词的首字母大写,其余的都小写。例如 Content-Type,User-Agent。
所以如果说在实际的开发中 Get 方法无法满足需求,需要直接访问 Header 的 map 结构,那么一定要注意这一点。
- 本文标题:Golang 操作 HTTP Header 的一个小细节
- 本文作者:kenticny
- 创建时间:2020-01-30 22:34:10
- 本文链接:https://luyun.io/2020/01/30/golang-operate-http-header-question-detail/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!