gin源码-获取请求参数
gin框架是如何获取请求参数的,我们以获取get参数为例,写一个简单的demo如下,最终得到调用链路。
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(200, c.Query("phone"))
})
_ = r.Run(":8000")
}
把关注点放在获取phone这个get参数上,得到的调用链路如下:
|-goroutine-50 created by net/http.(*Server).Serve.func3
|-net/http.(*conn).serve
|-w = net/http.(*conn).readRequest() // 获取请求
|-net/http.serverHandler.ServeHTTP(w, w.req) // 传递w.req
|-github.com/gin-gonic/gin.(*Engine).ServeHTTP // c.Request=w.req
|-github.com/gin-gonic/gin.(*Engine).handleHTTPRequest
|-github.com/gin-gonic/gin.LoggerWithConfig.func1
|-github.com/gin-gonic/gin.CustomRecoveryWithWriter.func1
|-main.main.func1
|-github.com/gin-gonic/gin.(*Context).Query // 最终解析c.Request.URL获取所有get参数
|-github.com/gin-gonic/gin.(*Context).GetQueryArray
|-net/url.(*URL).Query
|-sync.(*Pool).Put
|-net/http.(*response).finishRequest
可以看到主要是解析c.Request.URL得到get参数,而c.Request是通过net/http包的readRequest方法获取的。把关注点放在net/http.(*conn).readRequest()的执行流程上,得到:
|-w = net/http.(*conn).readRequest()
|-w.req = net/http.readRequest()
|-tp := net/http.newTextprotoReader()
|-s = tp.ReadLine() // 读取请求体的第一行
|-req.Method, req.RequestURI, req.Proto = parseRequestLine(s) // 解析"GET /index.html HTTP/1.1"
|-req.URL = url.ParseRequestURI(req.RequestURI) // 设置req.URL
|-mimeHeader := tp.ReadMIMEHeader() // 解析请求体的其他Key:value
|-req.Header = Header(mimeHeader) // 设置req.Header
|-readTransfer(req, b) // 设置req.Body