概述
在上一篇的基础之上继续实现前缀路由的功能。
首先说明一下这边说的前缀路由的概念。在上一篇的Web服务的基础上,我们对于路由可以有两种处理方式:
-
一种是所有的路由都挂载到根路径 ‘/’ 上边,举例说明,如果有一个登录和登出功能,我们可以这么来写
router.GET("/user/login", loginHandler) router.GET("/user/logout", logoutHandler)
当然这也是最为直观和容易理解的方式。
-
另一种是将有共通路径前缀的路由集合在一块,例如按照Gin的写法:
user := route.Group("/user") { user.GET("/login", loginHandler) user.GET("/logout", logoutHandler) }
当然各有各的好处了, 这种方式的方便之处在于,如果要对 “/user” 前缀的路由统一做处理(比如增加鉴权功能),就只需要在最上层加上处理逻辑,无需对每一个路由重复添加。尤其是在Gin里边,搭配后边会介绍的中间件一块使用,会显得更为方便。
接下来就介绍Gin里边如何实现的这一功能。同时我们慢慢的构建一个框架应该有的样子。
使用框架的目的是什么,我的理解是隐藏重复和底层的细节,使其作为一个可重复的抽象,让开发更为快速和便捷。前两篇都是直接用一个文件搭建了Web服务,现在我们开始真正的做一个抽象。
我们先抽象出来一个引擎 Engine,那么这个Engine里边应该有什么东西,很直观的,我们需要上一篇讲到的路由功能,以及这一篇讲到的路由前缀。定义如下:
Engine struct {
*RouterGroup
router *httprouter.Router
}
假设我们已经完成了这个 Engine, 我们需要一个启动函数
func (engine *Engine) Run(addr string) {
http.ListenAndServe(addr, engine)
}
看起来很简单,就是把上一篇中最后的启动函数 http.ListenAndServe 放到了Run里边而已。 区别只是把 engine 当作了第二个参数传入。而第二个参数其实只是 interface, 里边有一个函数
ServeHTTP(ResponseWriter, *Request)
所以只要 engine 也实现了这个函数,就能作为第二个参数了,那我们就实现一个。
// ServeHTTP makes the router implement the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
engine.router.ServeHTTP(w, req)
}
也是很简单,只是调用了 engine里边 httprouter.Router 的 ServeHTTP。
我们已经有了启动函数,接下去看看初始化的过程。先看engine中RouterGroup的定义
// HandlerFunc .
HandlerFunc func(*Context)
// Context .
Context struct {
Req *http.Request
Writer http.ResponseWriter
Params httprouter.Params
handler HandlerFunc
engine *Engine
}
// RouterGroup .
RouterGroup struct {
Handler HandlerFunc
prefix string
parent *RouterGroup
engine *Engine
}
这边定义了一个Context,这个是gin中最重要的数据结构之一。它把request的Req、Write以及Params都包在了里边。所以初始化的过程也就明确了
func New() *Engine {
engine := &Engine{}
engine.RouterGroup = &RouterGroup{nil, "", nil, engine}
engine.router = httprouter.New()
return engine
}
接下去定义group的时候,创建一个新的 RouterGroup
// Group .
func (group *RouterGroup) Group(component string) *RouterGroup {
prefix := path.Join(group.prefix, component)
return &RouterGroup{
Handler: nil,
parent: group,
prefix: prefix,
engine: group.engine,
}
}
然后调用
user.GET("/login", loginHandler)
的时候需要把对应的loginHandler加入到router的路由配置中
// GET is a shortcut for router.Handle("GET", path, handle)
func (group *RouterGroup) GET(path string, handler HandlerFunc) {
group.Handle("GET", path, handler)
}
// Handle .
func (group *RouterGroup) Handle(method, p string, handler HandlerFunc) {
p = path.Join(group.prefix, p)
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
group.createContext(w, req, params, handler).Next()
})
}
func (c *Context) Next() {
c.handler(c)
}
从上边的代码可以看出, user.GET 实际上就是先把routerGroup的前缀路径组合起来,然后将对应的路径和handler加入到httprouter里边。
同样的,类似GET方法的处理, 我们能定义其他的比如POST、DELETE的方法实现:
// POST is a shortcut for router.Handle("POST", path, handle)
func (group *RouterGroup) POST(path string, handler HandlerFunc) {
group.Handle("POST", path, handler)
}
// GET is a shortcut for router.Handle("GET", path, handle)
func (group *RouterGroup) GET(path string, handler HandlerFunc) {
group.Handle("GET", path, handler)
}
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (group *RouterGroup) DELETE(path string, handler HandlerFunc) {
group.Handle("DELETE", path, handler)
}
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (group *RouterGroup) PATCH(path string, handler HandlerFunc) {
group.Handle("PATCH", path, handler)
}
// PUT is a shortcut for router.Handle("PUT", path, handle)
func (group *RouterGroup) PUT(path string, handler HandlerFunc) {
group.Handle("PUT", path, handler)
}
这样一个最简单的框架其实就已经成形了, 那么怎么使用这个框架呢, 我们把上一篇的main.go文件进行一下修改。
package main
import (
"github.com/harleylau/myGin/v0.1/gin"
)
func v1IndexLoginfunc(c *gin.Context) {
c.String(200, "login")
}
func v1IndexSubmitfunc(c *gin.Context) {
c.String(200, "submit")
}
func main() {
r := gin.New()
// Simple group: v1
v1 := r.Group("/v1")
{
v1.GET("/login", v1IndexLoginfunc)
v1.GET("/submit", v1IndexSubmitfunc)
}
// Listen and server on 0.0.0.0:8080
r.Run(":8080")
}
具体的代码实现可以参见github: https://github.com/harleylau/myGin/tree/master/v0.1
下一篇介绍Web框架中的中间件技术。
最后
以上就是忧伤大侠为你收集整理的跟Gin一块搭建自己的web框架(三)的全部内容,希望文章能够帮你解决跟Gin一块搭建自己的web框架(三)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复