正文
一、 设置WriteHeader的顺序问题前端
以前遇到个问题,在一段代码中这样设置WriteHeader,最后在header中取Name时怎么也取不到。java
w.WriteHeader(201) w.Header().Set("Name", "my name is smallsoup")复制代码
用 golang 写 http server 时,能够很方即可经过 w.Header.Set(k, v) 来设置 http response 中 header 的内容。可是须要特别注意的是:某些时候不只要修改 response的header ,还要修改 response的StatusCode。修改response的StatusCode 能够经过:w.WriteHeader(code) 来实现,例如:python
w.WriteHeader(404)复制代码
若是这两种修改一块儿作,就必须让 w.WriteHeader 在全部的 w.Header.Set 以后,由于 w.WriteHeader 后 Set Header 是无效的。golang
并且必须是在 w.Write([]byte("HelloWorld")) 以前,不然会报 http: multiple response.WriteHeader calls 由于其实调用w.Write的时候也会调用WriteHeader()方法,而后将w.wroteHeader置为true,再次调WriteHeader()则会判断wroteHeader,若是是true则会报错,并且本次调用不生效。面试
能够看如下源码说明WriteHeader必须在Write以前调用。spring
func (w *response) WriteHeader(code int) { if w.conn.hijacked() { w.conn.server.logf("http: response.WriteHeader on hijacked connection") return } //第二次WriteHeader()进来知足if条件就报错直接return if w.wroteHeader { w.conn.server.logf("http: multiple response.WriteHeader calls") return } //第一次write()进来这里会将w.wroteHeader置为true w.wroteHeader = true w.status = code if w.calledHeader && w.cw.header == nil { w.cw.header = w.handlerHeader.clone() } if cl := w.handlerHeader.get("Content-Length"); cl != "" { v, err := strconv.ParseInt(cl, 10, 64) if err == nil && v >= 0 { w.contentLength = v } else { w.conn.server.logf("http: invalid Content-Length of %q", cl) w.handlerHeader.Del("Content-Length") } } }复制代码
二、 go会对Header中的key进行规范化处理docker
go会对Header中的key进行规范化处理,因此在获取response的Header中的K,V值时必定要当心。编程
reader.go中非导出方法canonicalMIMEHeaderKey中有这样一段,会将header的key进行规范化处理。数组
1)reader.go中定义了isTokenTable数组,若是key的长度大于127或者包含不在isTokenTable中的字符,则该key不会被处理。服务器
2)将key的首字母大写,字符 - 后的单词的首字母也大写。
分析以下源码,能够解释对key的大写处理:
for i, c := range a { // 规范化:首字母大写 // - 以后单子的首字母大写 // 如:(Host, User-Agent, If-Modified-Since). if upper && 'a' <= c && c <= 'z' { //大写转小写 c -= toLower } else if !upper && 'A' <= c && c <= 'Z' { //小写转大写 c += toLower } //从新给key数组赋值 a[i] = c //设置大小写标志位 upper = c == '-' // for next time }复制代码
正确的调用方式:
服务器:myServer.go
package main import ( "net/http" ) func main() { http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request){ w.Header().Set("name", "my name is smallsoup") w.WriteHeader(500) w.Write([]byte("hello world\n")) }) http.ListenAndServe(":8080", nil) }复制代码
客户端:
myHttp.go:
package main import ( "fmt" "io/ioutil" "net/http" ) func main() { myHttpGet() } func myHttpGet() { rsp, err := http.Get("http://localhost:8080") if err != nil { fmt.Println("myHttpGet error is ", err) return } defer rsp.Body.Close() body, err := ioutil.ReadAll(rsp.Body) if err != nil { fmt.Println("myHttpGet error is ", err) return } fmt.Println("response statuscode is ", rsp.StatusCode, "\nhead[name]=", rsp.Header["Name"], "\nbody is ", string(body)) }复制代码
1.运行服务器
go run myServer.go
2.运行客户端
go run myHttp.go
输出以下:statuscode是咱们设置的500,Name也取到了值。
关于go、docker、k8s相关学习资源关注文末公众号后回复【1】获取
本公众号免费提供csdn下载服务,海量IT学习资源,若是你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括但不限于java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端 等资源。同时咱们组建了一个技术交流群,里面有不少大佬,会不定时分享技术文章,若是你想来一块儿学习提升,能够公众号后台回复【2】,免费邀请加技术交流群互相学习提升,会不按期分享编程IT相关资源。
扫码关注,精彩内容第一时间推给你