2019独角兽企业重金招聘Python工程师标准>>>
在入口函数main()
的default
分支中,对路由进行了注册,现在分析下。
##main()中路由注册相关代码
源码:
httpRouter := httptreemux.New()
// Blog and pages as http
server.InitializeBlog(httpRouter)
server.InitializePages(httpRouter)
// Admin as http
server.InitializeAdmin(httpRouter)
// Start http server
log.Println("Starting server without HTTPS support. Please enable HTTPS in " + filenames.ConfigFilename + " to improve security.")
log.Println("Starting http server on port " + httpPort + "...")
err := http.ListenAndServe(httpPort, httpRouter)
if err != nil {log.Fatal("Error: Couldn't start the HTTP server:", err)
}
###httptreemux.New()
func New() *TreeMux {root := &node{path: "/"}return &TreeMux{root: root,NotFoundHandler: http.NotFound,MethodNotAllowedHandler: MethodNotAllowedHandler,HeadCanUseGet: true,RedirectTrailingSlash: true,RedirectCleanPath: true,RedirectBehavior: Redirect301,RedirectMethodBehavior: make(map[string]RedirectBehavior),PathSource: RequestURI,}
}
可以看到他返回了一个实例化的结构体TreeMux
,这个结构体注册了根路径/
,此外还包含一些默认的handle,如http.NotFound
:
// NotFound replies to the request with an HTTP 404 not found error.
func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
###server.InitializeBlog(httpRouter)
func InitializeBlog(router *httptreemux.TreeMux) {// For indexrouter.GET("/", indexHandler)router.GET("/:slug/", postHandler)router.GET("/page/:number/", indexHandler)// For authorrouter.GET("/author/:slug/", authorHandler)router.GET("/author/:slug/:function/", authorHandler)router.GET("/author/:slug/:function/:number/", authorHandler)// For tagrouter.GET("/tag/:slug/", tagHandler)router.GET("/tag/:slug/:function/", tagHandler)router.GET("/tag/:slug/:function/:number/", tagHandler)// For serving asset filesrouter.GET("/assets/*filepath", assetsHandler)router.GET("/images/*filepath", imagesHandler)router.GET("/content/images/*filepath", imagesHandler) // This is here to keep compatibility with Ghostrouter.GET("/public/*filepath", publicHandler)
}
这里使用了route.GET()
函数注册路由,我们看下router.GET("/", indexHandler)
:
// Syntactic sugar for Handle("GET", path, handler)
func (t *TreeMux) GET(path string, handler HandlerFunc) {t.Handle("GET", path, handler)
}
t.Handle("GET", path, handler)
:
func (t *TreeMux) Handle(method, path string, handler HandlerFunc) {if path[0] != '/' {panic(fmt.Sprintf("Path %s must start with slash", path))}addSlash := falseif len(path) > 1 && path[len(path)-1] == '/' && t.RedirectTrailingSlash {addSlash = truepath = path[:len(path)-1]}//将path注册到root子节点中去,并返回子节点的引用node := t.root.addPath(path[1:], nil)if addSlash {node.addSlash = true}//最终注册路由node.setHandler(method, handler)
}
node.setHandler(method, handler):
func (n *node) setHandler(verb string, handler HandlerFunc) {if n.leafHandler == nil {n.leafHandler = make(map[string]HandlerFunc)}_, ok := n.leafHandler[verb]if ok {panic(fmt.Sprintf("%s already handles %s", n.path, verb))}n.leafHandler[verb] = handler
}
剩下的路由注册server.InitializeBlog(httpRouter)
,server.InitializePages(httpRouter)
,server.InitializeAdmin(httpRouter)
都大同小异。
这里只是介绍了路由注册的整体流程,其中最复杂的地方是func (t *TreeMux) Handle(method, path string, handler HandlerFunc)
中的node := t.root.addPath(path[1:], nil)
函数,不过源码有详细的注释,有兴趣的自行研究。