3

httptest WriteHeader无效问题

 2 years ago
source link: https://studygolang.com/articles/35345
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

httptest WriteHeader无效问题

uuid · 大约8小时之前 · 6 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    

测试一个调用http接口时,使用了httptest.NewServer来mock一个http服务端,在验证响应异常状态码时发现奇怪问题,明明设置了异常状态码,但是http.Get始终返回的状态码都是正常的200:

mockHttpSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
    w.WriteHeader(http.StatusBadRequest)
}))
resp , err:= http.Get(mockHttpSrv.URL)
if err != nil {
    return
}
defer resp.Body.Close()
fmt.Println(resp.StatusCode) // 输出200

查阅WriteHeader的文档时才发现原来当w.WriteHeader没明确调用时,默认第一次调用Write方法时,会隐式的触发WriteHeader(http.StatusOK):

// WriteHeader sends an HTTP response header with the provided
// status code.
//
// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).
// Thus explicit calls to WriteHeader are mainly used to
// send error codes.
//
// The provided code must be a valid HTTP 1xx-5xx status code.
// Only one header may be written. Go does not currently
// support sending user-defined 1xx informational headers,
// with the exception of 100-continue response header that the
// Server sends automatically when the Request.Body is read.
WriteHeader(statusCode int)

我的单测代码将WriteHeader写在了Write方法之后,所以默认会先触发了WriteHeader(http.StatusOK)。

但是,为什么后来我调用WriteHeader(http.StatusBadRequest)会无效呢,正常不是应该覆盖前面的方法才对?!

认真阅读了 WriteHeader源码,原来WriteHeader只允许写入一次Header(通过一个布尔变量:wroteHeader,写入后被标志为true,再次调用就直接return):

// WriteHeader implements http.ResponseWriter.
func (rw *ResponseRecorder) WriteHeader(code int) {
   if rw.wroteHeader {
      return
   }
   rw.Code = code
   rw.wroteHeader = true
   if rw.HeaderMap == nil {
      rw.HeaderMap = make(http.Header)
   }
   rw.snapHeader = rw.HeaderMap.Clone()
}

这样问题就清晰了,是我WriteHeader顺序写错了,应该放在Write方法之前。

WriteHeader只能调用一次,如果一开始先调用Write,默认会触发WriteHeader(http.StatusOK),后续再调用WriteHeader就无效。

所以在开发中如果要测试非200的状态时,需要先设置响应状态码WriteHeader(http.StatusBadRequest),然后再调用Write方法。

我的博客httptest WriteHeader无效问题 | 艺术码农的小栈


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK