Go Revel

之前介绍了 Go Revel - main函数分析 http://www.cnblogs.com/hangxin1940/p/3263775.html 最后会调用 `revel.Run(*port)` 开启服务。 `server.go`源码 https://github.com/robfig/revel/blob/master/server.go 大致流程: ![golang_server.Run](http://images.cnblogs.com/cnblogs_com/hangxin1940/508415/o_server.Run.png "golang_server.Run") 首先获取ip地址 address := HttpAddr if port == 0 { port = HttpPort } // If the port equals zero, it means do not append port to the address. // It can use unix socket or something else. if port != 0 { address = fmt.Sprintf("%s:%d", address, port) } 如果ip地址为0,则读取配置文件中的。 生成模板加载器: MainTemplateLoader = NewTemplateLoader(TemplatePaths) 这个模板加载器包含了当前项目模板的路径。 根据配置文件是否开启热代码加载: // The "watch" config variable can turn on and off all watching. // (As a convenient way to control it all together.) if Config.BoolDefault("watch", true) { MainWatcher = NewWatcher() Filters = append([]Filter{WatchFilter}, Filters...) } 这里会生成一个`Watcher`,并将它加入过滤器链,`Watcher`符合Filter接口。它会对监听目录的中文件的任何更改作出响应。 根据配置文件是否开启模板热加载: // If desired (or by default), create a watcher for templates and routes. // The watcher calls Refresh() on things on the first request. if MainWatcher != nil && Config.BoolDefault("watch.templates", true) { MainWatcher.Listen(MainTemplateLoader, MainTemplateLoader.paths...) } else { MainTemplateLoader.Refresh() } 同上,它会对模板目录进行监控 开启HTTP服务: Server = &http.Server{ Addr: address, Handler: http.HandlerFunc(handle), } 处理所有向`OnAppStart`注册过的方法: runStartupHooks() 开始监听并等待连接: if HttpSsl { ERROR.Fatalln("Failed to listen:", Server.ListenAndServeTLS(HttpSslCert, HttpSslKey)) } else { ERROR.Fatalln("Failed to listen:", Server.ListenAndServe()) } 这里会视情况来开启ssl 请求处理器: // This method handles all requests. It dispatches to handleInternal after // handling / adapting websocket connections. func handle(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Upgrade") == "websocket" { websocket.Handler(func(ws *websocket.Conn) { r.Method = "WS" handleInternal(w, r, ws) }).ServeHTTP(w, r) } else { handleInternal(w, r, nil) } } func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) { var ( req = NewRequest(r) resp = NewResponse(w) c = NewController(req, resp) ) req.Websocket = ws Filters[0](c, Filters[1:]) if c.Result != nil { c.Result.Apply(req, resp) } } 所有的http请求都会在这里被处理。 首先会判断是否为`websocket`链接,如果是则打上标记,并当作websocket处理,最终都会调用`handleInternal`。 在`handleInternal`中,首先会处理过滤器链: Filters[0](c, Filters[1:]) `Filters`是一个切片,存储`Filter`类型的方法 type Filter func(c *Controller, filterChain []Filter) `Filter`是一个固定参数的方法,并且内部方法实现为级联递归调用。每次掉用,会传入`controller`以及当前`Filters`长度-1的一个切片,在方法最后会递归调用下去,直到传入的`Filters`切片没有元素。 自己实现的`Controller`中的方法被调用之前,所有的请求数据都会被`Filter`过滤一边,比如根据请求信息来生成路由信息,根据请求参数来转换为正确的自定义类型,运行拦截器等等。 最后,会运行: c.Result.Apply(req, resp) `controller`的`Result`字段会在运行过滤器链时被赋值,有可能是处理路由时的`Result`(比如404),也有可能是自定义`controller`中的`Result`(正常处理)
原文地址:https://www.cnblogs.com/hangxin1940/p/3265538.html