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 版本的代码可以看出它的一些设计思路, 除此以外,理解基本的技术实现,对日常使用也很有好处。