Go httptest WriteHeader无效问题

背景

测试一个调用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方法。

我的博客: https://itart.cn/blogs/2021/practice/httptest-writeheader-invalid.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容