正文

一、 设置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相关资源。

扫码关注,精彩内容第一时间推给你

image