当我们在《 原地起飞,带你揭晓 Go web 框架底层原理!》这边文章中把请求全接管后,接下来我们要做的就是开始内部消化这些请求了。
现在我们需要开始封装我们自己的处理模块了。
首先我们需要新建一个名为 kun 的文件夹,你也可以用你自己喜欢的名字,用来存放我们的框架代码。
现在我们写项目大都使用的 go mod 来管理我们的依赖,所以我们也通过 go mod 来引入我们的库。
这样能起到解耦的作用,完事之后我们还能把这个模块放到我们的仓库里面。
工程里面的 go.mod 文件内容:
module kun-demo
go 1.17
require kun v0.0.1
replace kun => ./kun
kun文件夹里面的 go.mod 文件内容:
module kun
go 1.17
对于不知道为什么要这样写的同学,可以去补一补 go mod 的基础知识哦,这里不做展开讲解。
首先我们先来看下,这篇文章最后要达到的使用效果:
func main() {
engine := kun.New()
engine.GET("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
})
engine.Run(":8081")
}
我们模仿了 gin 框架:
我们只需要调用下 kun 模块里面的 New 方法就可以得到一个引擎,随后就可以挂载我们的路由方法,最后直接 Run 就跑起来了。
要实现上面的效果,最关键的点就是上一篇文章里面提到的:
go 基础 http 库,只要是实现了 ServeHTTP(*w* http.ResponseWriter, *req* http.Request)
这个方法就可以给挂到 http 里面。
所以我们只需要新建一个结构体,随后实现这个方法即可。
知道了关键点,下面就开始写我们的模块代码:
在 kun.go 写上最核心的代码:
// 从定义方法
type HandleFun func(http.ResponseWriter, *http.Request)
// 核心结构体
type Engine struct {
router map[string]HandleFun
}
func New() *Engine {
return &Engine{
router: make(map[string]HandleFun,0),
}
}
//ServeHTTP 关键方法 实现 Handler 的接口
func (this *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
if handler,ok := this.router[key];ok {
handler(w, req)
}else{
fmt.Fprintf(w,"404 Not Found: %s\n", req.URL)
}
}
// 发射
func (this *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, this)
}
这里我们声明了一个 Engine 的结构体,里面我们声明了一个 map 类型的路由,这是为了方便挂载不同的方法。
同时因为 func(http.ResponseWriter, *http.Request)
这个方法会被经常用到,所以我们对他进行了重命名。
最关键的就是 ServeHTTP 方法了:
当我们的请求过来时,我们把他的 method 和 path 两个参数,合并起来,当做 key 去 router 里面查找这请求的处理方法,你也可以使用其他的处理方式。
最后就是 run 起来,把自己挂载到 http 里面。
这就是最最最核心的几行代码了!
上面写完了核心代码,接下来就开始完善周边的方法,让调用的人使用起来更加的便利。
如果你不完善,其实也通过修改 Engine 里面的 router 属性,也能达到最后的效果,但是这样非常不友好。
所以,这里我们再加写两个方法!
func (this *Engine) AddRouter(method string, pattern string, handler HandleFun) {
key := method + "-" + pattern
this.router[key] = handler
}
func (this *Engine) GET(pattern string, handler HandleFun) {
this.AddRouter("GET",pattern,handler)
}
你还可以加上 POST、PUT、DELETE 等方法的挂载入口。
我这里就不写了,大家自己完善吧。
我们的最初级的封装就完成了,现在你可以任意的挂载方法了。
接下来我会再进一步的迭代,下一篇文章我们会融入上下文功能,让我们的框架更加的好用