之前有篇文章比较浅显的分析了一下golang的服务器如何实现,还有<代码>处理程序,DefaultServeMux, HandlerFunc> 代码的用处。
我们现在已经明白了<代码> DefaultServeMux> 代码就是存放<代码>模式代码>和<代码>处理程序代码>的地方,我们称其为路由,那么我们可能会想,既然golang能够实现这个路由,我们能否也模仿一个呢?
首先我们需要一个能够保存客户端的请求的一个容器(路由)。
<>强创建路由结构体强>
CopyRouter struct类型{ 路由器map [string] [string] http.HandlerFunc地图 } >之前在这里我们创建了一个像DefaultServeMux的路由。
<强>客户端请求存入路由强>
func (c * CopyRouter) HandleFunc(方法、模式字符串处理http.HandlerFunc) { 如果方法==" { 恐慌(“方法不能空!”) } 如果模式==" { 恐慌(”模式不能空!”) } 如果_,好的:=c.router[方法](模式);好{ 恐慌(“模式存在!”) } 如果c。路由器==nil { c。路由器=使(map [string] map [string] http.HandlerFunc) } 如果c。路由器[方法]==nil { c。路由器[方法]=使(map [string] http.HandlerFunc) } c。路由器[方法][模式]=处理 } >之前这里我们模仿源码中的<代码> ServeMux> 代码将每一个URL所对应的处理程序保存起来。
<>强实现处理器接口强>
func (c * CopyRouter) ServeHTTP http (w。ResponseWriter r * http.Request) { 好的,如果f:=c.router [r.Method] [r.URL.String ());好{ f。ServeHTTP (w, r) } } >之前在这里为什么要实现这个处理器接口,因为我们发现在ListenAndServe方法中,最后会调用<代码> h。ServeHTTP (w, r), 代码>那么我们就只需要让我们定义的路由实现<代码>处理程序代码>接口就可以了。
<强>获取一个路由强>
* CopyRouter func NewRouter () { 返回新(CopyRouter) } >之前到这里,我们自己定义的路由就完成了,我们来看看使用方法。
func sayHi http (w。ResponseWriter r * http.Request) { fmt.Fprint (w,“嗨”) } 函数main () { copyRouter:=copyrouter.NewRouter () copyRouter。HandleFunc(“获得”、“/sayHi”sayHi) log.Fatal (http。ListenAndServe (“localhost: 8080”, copyRouter)) } >之前这样就完成了一个高仿版的自定义路由,是不是和golang提供给我们的<代码> ServeMux> 代码很像,当然我们这个路由是一个低配版的,还有很多细节没有处理。
现在再看看,我们的主要函数里面的代码不是很美观,每一次都要写得到或者发布方法,那么我们能否提供一个比较美观的方式呢?可以,那么我们再封装一下。
func (c * CopyRouter)得到(模式字符串处理程序http.HandlerFunc) { c。HandleFunc(“得到”模式,处理程序) } func (c * CopyRouter)帖子(模式字符串处理程序http.HandlerFunc) { c。HandleFunc (“POST”模式,处理程序) } … >之前然后再修改一下调用方式。
copyRouter.GET (“/sayHi”, sayHi)现在看起来是不是就美观很多了吗?是的,很多web框架也是这样,为什么用起来就感觉很流畅,因为这些大神们就是站在我们开发者的角度来考虑问题,提供了很方便的一些用法,封装的很完善。
再考虑一下,我们这个自定义的路由还能做些什么,如果我们要记录每一次的访问请求,该如何处理呢?也很简单,我们只需要将逻辑写在<代码> ServeHTTP 代码>方法中就可以了,稍微修改一下我们的代码。
func (c * CopyRouter) ServeHTTP http (w。ResponseWriter r * http.Request) { 好的,如果f:=c.router [r.Method] [r.URL.String ());好{ func(处理程序http.Handler) { 开始:=time.Now () 日志。Printf("请求(% s)开始时间为:% v \ n”, r.URL.String(),开始) f。ServeHTTP (w, r) 日志。Printf("请求(% s)完成时间为:% v \ n”, r.URL.String (), time.Since(开始) }(f) } }Golang中的路由使用详解