最近在学习一个七天系列课程,而后在这里对本人学习到的货色进行一个总结。明天实现的是web框架中的路由映射。
Http-Net包
在实现这个路由解析器的时候,咱们首先要明确go本来的http/net包是如何实现路由解析定向的。
其中重要的函数
// HandleFunc registers the handler function for the given pattern// in the DefaultServeMux.// The documentation for ServeMux explains how patterns are matched.func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler)}
这里的函数参数,第一个是门路的函数,第二个是处理函数handle,这个函数最初调用的其实就是
// The HandlerFunc type is an adapter to allow the use of// ordinary functions as HTTP handlers. If f is a function// with the appropriate signature, HandlerFunc(f) is a// Handler that calls f.type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r)}
也就是说实现了handler的接口,那么就有了解决申请的能力。那么咱们来看实现handler这个接口的条件是什么。这里浮浅的解释一下这个go接口的实现,在go语言中是反对鸭子类型的,所以咱们只有实现了接口外面的办法,那么就实现了这个接口。
handler接口:
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
实现这个接口咱们就有能力解决网络的申请了。然而其中咱们还有货色须要咱们去理解
首先就是咱们如何获取网络申请中的门路呢?
其实这个很简略,在咱们的Request中其实是蕴含了申请的门路的,获取的形式:
req.URL.Path
获取了过后咱们就能够将申请的门路和对应的函数的建设起映射的关系。
在这里咱们简略的演示了一下下面提到的根本的应用,也就是实现根本的网络申请解决。
type engine struct {}func (e *engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { switch req.URL.Path { case "/": fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path) case "/hello": for k, v := range req.Header { fmt.Fprintf(w, "Header[%q] = %q\n", k, v) } default: fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL) }}func main() { en := new(engine) log.Fatal(http.ListenAndServe(":9999", en))}
而后咱们就能够开始实现框架的第一步,路由映射关系。
框架映射构造
最初实现的源码:
package geeimport ( "fmt" "net/http")// HandlerFunc defines the request handler used by geetype HandlerFunc func(http.ResponseWriter, *http.Request)// Engine implement the interface of ServeHTTPtype Engine struct { router map[string]HandlerFunc}// New is the constructor of gee.Enginefunc New() *Engine { return &Engine{router: make(map[string]HandlerFunc)}}func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) { key := method + "-" + pattern engine.router[key] = handler}// GET defines the method to add GET requestfunc (engine *Engine) GET(pattern string, handler HandlerFunc) { engine.addRoute("GET", pattern, handler)}// POST defines the method to add POST requestfunc (engine *Engine) POST(pattern string, handler HandlerFunc) { engine.addRoute("POST", pattern, handler)}// Run defines the method to start a http serverfunc (engine *Engine) Run(addr string) (err error) { return http.ListenAndServe(addr, engine)}func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { key := req.Method + "-" + req.URL.Path if handler, ok := engine.router[key]; ok { handler(w, req) } else { fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL) }}
在这里咱们能够看到的是咱们这里的实现的成果和gin很像,这里咱们建设了一个map,用来映射路由和函数,而后这里咱们在存储的时候,咱们还将申请的办法进行了一个存储,也就是说雷同的门路然而不同的申请形式他最初调用的函数也是不一样的。