为什么在gin的方法*Context.Render(code int, r render.Render)中先设置response code?

Why response code is set firstly in method *Context.Render(code int, r render.Render) of gin?

Gin封装了一些构造response的方法,比如方法*Context.JSON(code int, obj interface{})*Context.String(code int, format string, values ...interface{})。这些方法都是调用方法*Context.Render(code int, r render.Render).

// Render writes the response headers and calls render.Render to render data.
func (c *Context) Render(code int, r render.Render) {
    c.Status(code)

    if !bodyAllowedForStatus(code) {
        r.WriteContentType(c.Writer)
        c.Writer.WriteHeaderNow()
        return
    }

    if err := r.Render(c.Writer); err != nil {
        panic(err)
    }
}

我想知道为什么Render方法会调用Status方法,它会先调用ResponseWriter.WriterHeader(statusCode int)方法来设置HTTP响应码。

r.Render(c.Writer) 会将相应的 Content-Type 写入响应。显然它发生在设置状态代码之后(调用方法 WriterHeader 之后)。根据对方法 ResponseWriter.Header() 的评论,在调用 WriteHeader(或 Write)后更改 header 映射没有任何效果,除非修改后的 header 是拖车。但是设置 Content-Type 在 Gin 中有效。

func writeContentType(w http.ResponseWriter, value []string) {
    header := w.Header()
    if val := header["Content-Type"]; len(val) == 0 {
        header["Content-Type"] = value
    }
}

c.Writergin.ResponseWriter(可能是具体类型 gin.responseWriter),而不是 http.ResponseWriter。虽然它实现了相同的接口,但的实现方式不同。 Gin 的 WriteHeader 不会 立即发送 headers;它只是将 code 存储在编写器内部,WriteHeaderNow 使用存储的代码从 net/http 调用“真实的”WriteHeader

WriteHeaderNow在没有body的情况下直接被你引用的函数调用;如果有 body,则 WriteHeaderNow 在第一个 Write 到 body 被调用。