Context结构
Context结构定义
type Context struct {
// responseWriter对ResponseWriter封装
writermem responseWriter
// http请求及响应writer
Request *http.Request
Writer ResponseWriter
// 键值对切片类型
Params Params
// HandlerFunc切片类型
handlers HandlersChain
index int8
fullPath string
// 当前上下文属于哪个引擎
engine *Engine
// 每个请求上下文专用键值对
Keys map[string]interface{}
// *Error切片类型,Error封装error类型
//所有使用当前上下文的handlers/middlewares对应的出错信息都存放在这里
Errors errorMsgs
// Accepted defines a list of manually accepted formats for content negotiation.
Accepted []string
// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
queryCache url.Values
// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
// or PUT body parameters.
formCache url.Values
}
url.Values
类型定义
// key类型为string,value类型为[]string,一个key对应多个value
type Values map[string][]string
方法集
// 通过key获取对应的value,如果存在,总会返回v[key][0],否则为""
func (v Values) Get(key string) string
// 设置键值对key/[]string{value},若key之前有数据,会被替换掉
func (v Values) Set(key, value string)
// 给key的value列表增加数据value
func (v Values) Add(key, value string)
// 删除key及对应的所有values
func (v Values) Del(key string)
有HTTP请求时,gin处理流程:
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}
func (engine *Engine) handleHTTPRequest(c *Context) {
httpMethod := c.Request.Method
rPath := c.Request.URL.Path
unescape := false
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
rPath = c.Request.URL.RawPath
unescape = engine.UnescapePathValues
}
rPath = cleanPath(rPath)
// 通过给定的HTTP请求方法找到方法树
t := engine.trees
for i, tl := 0, len(t); i < tl; i++ {
if t[i].method != httpMethod {
continue
}
root := t[i].root
// 找到树中的路由
value := root.getValue(rPath, c.Params, unescape)
if value.handlers != nil {
c.handlers = value.handlers
c.Params = value.params
c.fullPath = value.fullPath
c.Next()
c.writermem.WriteHeaderNow()
return
}
if httpMethod != "CONNECT" && rPath != "/" {
if value.tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c)
return
}
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
return
}
}
break
}
if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees {
if tree.method == httpMethod {
continue
}
if value := tree.root.getValue(rPath, nil, unescape); value.handlers != nil {
c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
}
}
}
c.handlers = engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body)
}