gin 是一个 golang 的 http 框架。
0. 运行
- httprouter 版本会导致
engine.router.NotFound = engine.handle404
赋值时类型不匹配。需要找旧一些的httprouter版本。
- 在跑例子的时候需要引入0.1版,如果已经安装了正式版的,需要引入正确的版本。
2. Engine
engine对象包含了 httprouter 复用器和一个全局中间件列表。这里用到了结构体的 匿名嵌入 , 使得 engine 类可以使用 RouterGroup 类的方法。在下面的函数中 Use() 和 Group() 以及 Handle() 函数跟其他 RouterGroup 的方法都可以以类似继承的方式被 engine 对象使用。
其中 Use() 函数在 RouterGroup 的 []Handler 切片中添加新的中间件,Group() 函数接受路由组前缀字符串 和处理方法切片(变参)。
所以,以下语句实现的效果相同
api := r.Group("api") api.Use(AuthMiddleware, AuthMiddleware2) api := r.Group("/api", AuthMiddleware, AuthMiddleware2)
其实中间件和处理函数并没有本质的区别。需要重点看一下 Handle()函数。:
// Handle registers a new request handle and middlewares
// with the given path and method.
// The last handler should be the real handler, the other ones should be middlewares that can and should be shared among different routes.
// See the example code in github.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
p = path.Join(group.prefix, p)
handlers = group.combineHandlers(handlers)
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
group.createContext(w, req, params, handlers).Next()
})
}
3. Context
上面的 Handle() 方法需要用到一个函数 Next()
// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
// See example in github.
func (c *Context) Next() {
c.index++
s := int8(len(c.handlers))
for ; c.index < s; c.index++ {
c.handlers[c.index](c)
}
}
它是 Context 的方法。Context 对象是 gin 最重要的概念,它允许我们再中间件之间传递变量, 控制流,校验请求的 JSON,渲染 返回的 JSON 等。
Context struct {
Req *http.Request
Writer http.ResponseWriter
Keys map[string]interface{}
Errors []ErrorMsg
Params httprouter.Params
handlers []HandlerFunc
engine *Engine
index int8
}
其中,正如我们上面提到的 Next() 的作用就是控制流。下面的 Get() 和 Set() 方法,通过操作 Contex.Keys 在中间件之间传递变量,其余函数用来校验请求和返回数据。
4. 总结
gin 作为一个轻量级而又高性能的 golang 框架,通过阅读其 0.1 版本的代码可以看出它的一些设计思路, 除此以外,理解基本的技术实现,对日常使用也很有好处。