关于golang:七天实现web框架路由映射

31次阅读

共计 2601 个字符,预计需要花费 7 分钟才能阅读完成。

最近在学习一个七天系列课程,而后在这里对本人学习到的货色进行一个总结。明天实现的是 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 gee

import (
    "fmt"
    "net/http"
)

// HandlerFunc defines the request handler used by gee
type HandlerFunc func(http.ResponseWriter, *http.Request)

// Engine implement the interface of ServeHTTP
type Engine struct {router map[string]HandlerFunc
}

// New is the constructor of gee.Engine
func 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 request
func (engine *Engine) GET(pattern string, handler HandlerFunc) {engine.addRoute("GET", pattern, handler)
}

// POST defines the method to add POST request
func (engine *Engine) POST(pattern string, handler HandlerFunc) {engine.addRoute("POST", pattern, handler)
}

// Run defines the method to start a http server
func (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,用来映射路由和函数,而后这里咱们在存储的时候,咱们还将申请的办法进行了一个存储,也就是说雷同的门路然而不同的申请形式他最初调用的函数也是不一样的。

正文完
 0