Context 是 Gin 最重要的数据结构,理解它的组成对深入使用 Gin 很有帮助。
Context 结构体的主要字段:
type Context struct {
Request *http.Request
Writer ResponseWriter
Params Params
handlers HandlersChain
index int8
fullPath string
engine *Engine
mu sync.RWMutex
Keys map[string]interface{}
Errors errorMsgs
Accepted []string
}
c.Request.Method
c.Request.URL
c.Request.Header
c.Request.Body
c.FullPath()
c.ClientIP()
c.ContentType()
c.IsWebsocket()
c.UserAgent()
c.Param("id")
c.Query("name")
c.DefaultQuery("name", "default")
c.PostForm("field")
c.DefaultPostForm("field", "default")
c.GetRawData()
c.GetHeader("Authorization")
c.GetHeaders()
c.JSON(200, data)
c.XML(200, data)
c.String(200, "text")
c.HTML(200, "template.html", data)
c.Data(200, "application/octet-stream", bytes)
c.File("path/to/file")
c.Redirect(302, "/new-url")
c.Set("key", value)
c.Get("key")
c.MustGet("key")
c.GetString("key")
c.GetInt("key")
c.GetFloat("key")
c.GetTime("key")
c.GetDuration("key")
c.Header("Content-Type", "application/json")
c.GetHeader("Authorization")
c.SetCookie("name", "value", 3600, "/", "", false, true)
c.Cookie("name")
c.Next()
c.Abort()
c.AbortWithStatus(401)
c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
c.IsAborted()
每个请求都会创建一个新的 Context:
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.Writer.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}
Context 使用 sync.Pool 复用,避免频繁创建对象。
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Any("/info", func(c *gin.Context) {
info := gin.H{
"method": c.Request.Method,
"path": c.Request.URL.Path,
"fullPath": c.FullPath(),
"clientIP": c.ClientIP(),
"contentType": c.ContentType(),
"userAgent": c.UserAgent(),
"headers": c.Request.Header,
"query": c.Request.URL.Query(),
"isAjax": c.GetHeader("X-Requested-With") == "XMLHttpRequest",
"isWebSocket": c.IsWebsocket(),
}
c.JSON(http.StatusOK, info)
})
r.Run(":8080")
}
Context 的 Writer 是对 http.ResponseWriter 的封装:
type ResponseWriter interface {
http.ResponseWriter
http.Hijacker
http.Flusher
http.CloseNotifier
Status() int
Size() int
WriteString(string) (int, error)
Written() bool
WriteHeaderNow()
Pusher() http.Pusher
}
常用操作:
c.Writer.Status()
c.Writer.Size()
c.Writer.Header()
c.Writer.Write([]byte("data"))
c.Writer.WriteString("text")
c.Writer.Flush()
r.POST("/body", func(c *gin.Context) {
body, err := c.GetRawData()
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.String(200, "Body: %s", string(body))
})
注意:GetRawData 只能读取一次,如果需要在多处使用,需要重新设置:
body, _ := c.GetRawData()
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
func isJSON(c *gin.Context) bool {
return strings.Contains(c.ContentType(), "application/json")
}
func isFormData(c *gin.Context) bool {
return strings.Contains(c.ContentType(), "application/x-www-form-urlencoded")
}
func isMultipart(c *gin.Context) bool {
return strings.Contains(c.ContentType(), "multipart/form-data")
}
Context 是 Gin 的核心,封装了请求和响应的所有操作。理解它的结构和方法分类,有助于快速找到需要的功能。记住 Context 是请求级别的,每个请求独立,生命周期从请求开始到响应结束。