Golang中的HTTP请求也是依赖Trees和net的Http库实现,Trees负责找到对应请求的调用连,ServeHttp负责触发请求,具体我们往下进一步分析。
下面是一个GoHTTP请求的简单的流程图,基本可以知道请求大概经过了哪些地方,由哪些模块进行处理了,接下来我将进一步详细的分析每个过程。
HTTP请求接收
go c.serve(connCtx) // 处理请求的入口,此处说明了所有请求都是独立协程
1.客户端请求到达Serve函数,通过c.serve发起独立请求,也就是说,go处理每个请求都是单独协程的,找到http请求过后,执行对应的HTTP服务。
serverHandler{c.server}.ServeHTTP(w, w.req) // 创建server处理器并执行触发ServeHTTP
2.获取对应的处理器,这里的处理器就是Gin之前实现的Engine,在New的时候创建的,具体的逻辑可以看我上一篇文章中最后所提到的,最后handler.ServeHTTP(rw, req),就前往了engine具体实现的ServeHTTP方法中去了。
- 拿到引擎请求的上下文。
- 给Engine对象的请求赋值。
- 执行handleHTTPRequest请求。
// ServeHTTP 这里就是Gin实现的ServeHTTP方法(这里和我们上一篇文章提到的Engine实现ServeHTTP有关
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)
}
请求处理
handleHTTPRequest负责进行进一步的请求处理,此函数主要的工作有这么几个。
1.通过RequestMethod匹配到对应的handler,这个是从trees提取的,也就是之前New初始化的时候新建的Trees,这里面存了所有的请求handler。
2.匹配到handler之后执行Handler,然后判断链式调用是否结束,如果没有C.Next继续执行下一个handler。
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
}
// 是否格式化多余的斜杠
if engine.RemoveExtraSlash {
rPath = cleanPath(rPath)
}
// 遍历树找到对应的调用handler链
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, c.skippedNodes, unescape)
if value.params != nil {
c.Params = *value.params
}
// 处理路由
if value.handlers != nil {
// 找到对应的handler,并赋值
c.handlers = value.handlers
c.fullPath = value.fullPath
c.Next()
c.writermem.WriteHeaderNow()
return
}
if httpMethod != http.MethodConnect && 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, c.skippedNodes, unescape); value.handlers != nil {
c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
}
}
}
// 找到对应的handler,并赋值
c.handlers = engine.allNoRoute
// 跑出异常
serveError(c, http.StatusNotFound, default404Body)
}