跳至主要內容

第一天:就从路由开始吧

程序员李某某原创Golang框架源码路由大约 2 分钟

第一天:就从路由开始吧

提示

本文是学习了大佬的Gee后动手写的Lee 参考链接

先看看原生写法

原生标准库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)
}
上次编辑于:
贡献者: ext.liyuanhao3