Go Revel - server.go 源码分析

之前介绍了 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

首先获取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)

controllerResult字段会在运行过滤器链时被赋值,有可能是处理路由时的Result(比如404),也有可能是自定义controller中的Result(正常处理)

posted on   黑暗伯爵  阅读(1850)  评论(0编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示