英文:
Why response code is set firstly in method *Context.Render(code int, r render.Render) of gin?
问题
Gin封装了一些用于构建响应的方法,例如*Context.JSON(code int, obj interface{})
和*Context.String(code int, format string, values ...interface{})
。这些方法都会调用*Context.Render(code int, r render.Render)
方法。
// Render写入响应头并调用render.Render来渲染数据。
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
方法,而Status
方法会首先调用ResponseWriter.WriterHeader(statusCode int)
方法来设置HTTP响应代码。
r.Render(c.Writer)
将会向响应中写入相应的Content-Type。显然,这发生在设置状态码之后(在调用WriterHeader
方法之后)。根据ResponseWriter.Header()
方法的注释,在调用WriteHeader
(或Write
)之后修改头部映射是没有效果的,除非修改的头部是尾部。但是在Gin中设置Content-Type是有效的。
func writeContentType(w http.ResponseWriter, value []string) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = value
}
}
英文:
Gin has encapsulated some methods for constructing response, such as methods *Context.JSON(code int, obj interface{})
and *Context.String(code int, format string, values ...interface{})
. These methods all call the method *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)
}
}
I wonder why the Render
method call the method Status
which will set the HTTP response code by calling the method ResponseWriter.WriterHeader(statusCode int)
firstly.
r.Render(c.Writer)
will write Corresponding Content-Type to the response. Apparently it occurs after setting the status code (after calling method WriterHeader
). According to the comment on method ResponseWriter.Header()
, changing the header map after a call to WriteHeader
(or Write
) has no effect unless the modified headers are trailers. But setting Content-Type works in Gin.
func writeContentType(w http.ResponseWriter, value []string) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = value
}
}
答案1
得分: 2
c.Writer
是一个 gin.ResponseWriter
(可能是具体类型 gin.responseWriter
),而不是 http.ResponseWriter
。虽然它实现了相同的接口,但它的实现方式并不完全相同。Gin 的 WriteHeader
并不会立即发送头部信息,它只是将 code
内部存储在 writer 中,而 WriteHeaderNow
方法会使用存储的 code 调用 net/http
中的真正的 WriteHeader
方法。
在你引用的函数中,如果没有响应体,则直接调用 WriteHeaderNow
方法;如果有响应体,则在第一次对响应体进行写入时调用 WriteHeaderNow
。
英文:
c.Writer
is a gin.ResponseWriter
(probably the concrete type gin.responseWriter
), not an http.ResponseWriter
. While it implements the same interface, it doesn't do it in an identical way. Gin's WriteHeader
doesn't send the headers immediately; it just stores the code
internally in the writer, and WriteHeaderNow
calls the "real" WriteHeader
from net/http
with the stored code.
WriteHeaderNow
is called directly by the function you quoted in the case where there's no body; if there is a body, then WriteHeaderNow
gets called on the first Write
to the body.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论