Go Revel - server.go 源碼分析
之前介紹了 Go Revel - main函數(shù)分析 http://www.rzrgm.cn/hangxin1940/p/3263775.html
最后會調(diào)用 `revel.Run(*port)` 開啟服務(wù)。
`server.go`源碼 https://github.com/robfig/revel/blob/master/server.go
大致流程:

首先獲取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)
這個模板加載器包含了當(dāng)前項目模板的路徑。
根據(jù)配置文件是否開啟熱代碼加載:
// 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接口。它會對監(jiān)聽目錄的中文件的任何更改作出響應(yīng)。
根據(jù)配置文件是否開啟模板熱加載:
// 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()
}
同上,它會對模板目錄進(jìn)行監(jiān)控
開啟HTTP服務(wù):
Server = &http.Server{
Addr: address,
Handler: http.HandlerFunc(handle),
}
處理所有向`OnAppStart`注冊過的方法:
runStartupHooks()
開始監(jiān)聽并等待連接:
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`鏈接,如果是則打上標(biāo)記,并當(dāng)作websocket處理,最終都會調(diào)用`handleInternal`。
在`handleInternal`中,首先會處理過濾器鏈:
Filters[0](c, Filters[1:])
`Filters`是一個切片,存儲`Filter`類型的方法
type Filter func(c *Controller, filterChain []Filter)
`Filter`是一個固定參數(shù)的方法,并且內(nèi)部方法實現(xiàn)為級聯(lián)遞歸調(diào)用。每次掉用,會傳入`controller`以及當(dāng)前`Filters`長度-1的一個切片,在方法最后會遞歸調(diào)用下去,直到傳入的`Filters`切片沒有元素。
自己實現(xiàn)的`Controller`中的方法被調(diào)用之前,所有的請求數(shù)據(jù)都會被`Filter`過濾一邊,比如根據(jù)請求信息來生成路由信息,根據(jù)請求參數(shù)來轉(zhuǎn)換為正確的自定義類型,運行攔截器等等。
最后,會運行:
c.Result.Apply(req, resp)
`controller`的`Result`字段會在運行過濾器鏈時被賦值,有可能是處理路由時的`Result`(比如404),也有可能是自定義`controller`中的`Result`(正常處理)
浙公網(wǎng)安備 33010602011771號