第一天:就从路由开始吧
原创Golang框架源码路由大约 2 分钟
第一天:就从路由开始吧
先看看原生写法
原生标准库http服务端
func main() {
http.HandleFunc("/", handleFunc)
http.HandleFunc("/sayHello", handleSayHello)
http.ListenAndServe("localhost:8080", nil)
}
func handleFunc(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("vvv"))
}
func handleSayHello(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello"))
}
可以看到ListenAndServe这个函数有两个参数,一个是地址,另一个参数就是来做统一处理,也就是web框架的入口
http.Handler
这个参数是一个接口类型
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
只有一个方法 ServeHTTP 我们就需要定义一个结构体,绑定一个这个接口方法的实现
type Engine struct {} // 结构体
// 接口实现
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/":
fmt.Println("111111111111111")
case "/sayHello":
fmt.Println("2222222222")
default:
fmt.Println("3333333333333333")
}
}
如果用浏览器调用的,可能会发现每次都会打印default的逻辑,不要慌,那是因为浏览器每次刷新都会请求favicon.ico
路由
如何像gin那样,r.Get("/sayHello",handleFunc)调用呢? 这就需要定义一个路由字段了,路由本质上就是一个k,v映射,所以定义为一个map
type HandleFunc func(http.ResponseWriter, *http.Request)
type Engine struct {
router map[string]HandleFunc
}
调用r.Get("/sayHello",handleFunc)其实就是向map中添加映射
func (e *Engine) addRoute(method string, path string, handler HandleFunc) {
key := method + "_" + path
e.router[key] = handler
}
func (e *Engine) Get(path string, handleFunc HandleFunc) {
e.addRoute("GET", path, handleFunc)
}
func (e *Engine) Post(path string, handleFunc HandleFunc) {
e.addRoute("POST", path, handleFunc)
}
func (e *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, e)
}
这里将每个映射的key用请求方法_URL拼接表示 而gin中的Run方法就是对 http.ListenAndServe 方法的封装
func (e *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, e)
}
这里的第二个参数,我们将自己封装的 Engine 对象传进去,根据多态,底层就会调用我们的接口实现
实现的内部逻辑也很简单,就是从router这个map中取出对应的值,即处理函数,取出来之后直接调用即可
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
k := r.Method + "_" + r.URL.Path
// 取对应的处理函数
if handleFunc, ok := e.router[k]; ok {
handleFunc(w, r) // 调用
} else {
fmt.Fprintf(w, "404 NOT FOUND: %s\n", r.URL)
}
}
最后,还差一个实例化的方法
func New() *Engine {
return &Engine{router: make(map[string]HandleFunc)}
}
我们将这些代码放到 lee 这个包中 ./lee/lee.go
测试一哈
func main() {
e := lee.New()
e.Get("/sayHello", handleFunc)
e.Run("localhost:8080")
}
func handleFunc(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("vvv"))
}
完整代码
type HandleFunc func(http.ResponseWriter, *http.Request)
type Engine struct {
router map[string]HandleFunc
} // 结构体
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
k := r.Method + "_" + r.URL.Path
if handleFunc, ok := e.router[k]; ok {
handleFunc(w, r)
} else {
fmt.Fprintf(w, "404 NOT FOUND: %s\n", r.URL)
}
}
func (e *Engine) addRoute(method string, path string, handler HandleFunc) {
key := method + "_" + path
e.router[key] = handler
}
func New() *Engine {
return &Engine{router: make(map[string]HandleFunc)}
}
func (e *Engine) Get(path string, handleFunc HandleFunc) {
e.addRoute("GET", path, handleFunc)
}
func (e *Engine) Post(path string, handleFunc HandleFunc) {
e.addRoute("POST", path, handleFunc)
}
func (e *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, e)
}
