开坑第一问
What is Gin?
官网介绍:Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin。
Gin为什么那么好用呢?这与它背后无数开源大佬有关,作为插件式web框架,背后有着一个开源小生态给Gin提供大量的插件。本文也在这里浅谈一下自己在学习中的一些见解,希望对各位有所帮助。
Hello Word
以下简单10行代码,即可打开一个web服务。
go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
其中gin.H的另一名称为map[string]interface{},该类型使用频繁,Gin使用另一名称代替。 以上代码是不是有些难懂,那么好!上正菜。
gin.Engine
老友们可能疑惑汉叁老哥这案例里gin.Default
,是个什么东东?那你看到标题没,肯定和Engine
有关系啊。你在用你绝顶的智慧在意推理。。。答案呼之欲出,这不就是返回来一个Engine对象吗。既然都已经知道这些了,那接下来的解释就方便多了。
Engine是什么?引擎。顾名思义这是Gin中极为核心的东西,Engine 是 Gin 框架最重要的数据结构,它是框架的入口。我们通过 Engine 对象来定义服务路由信息、组装插件、运行服务。正如 Engine 的中文意思「引擎」一样,它就是框架的核心发动机,整个 Web 服务的都是由它来驱动的。
区别于现实世界中的引擎,Engine如同一个简单的包装箱,引擎底层的HTTP服务器是使用Go语言中内置的http server,Engine实为对此的封装,所以它用起来方便快捷。
gin.Default() 函数会生成一个默认的 Engine 对象,里面包含了 2 个默认的常用插件,分别是 Logger 和 Recovery,Logger 用于输出请求日志,Recovery 确保单个请求发生 panic 时记录异常堆栈日志,输出统一的错误响应。
scss
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
路由和路由组
提到路由,我们绕不开的一个概念就是路由树
了,这里我们不打算深究路由树
的原理,只简单介绍,有老哥想要进一步搞懂可去终于搞懂了Gin中的路由树转存失败。路由树
是 Gin
框架中核心概念之一,它采用了树的数据结构,准确来说就是 radix tree(压缩前缀树)
。
此先声明,本人水平有限,此处为自己的见解,想彻底搞懂路由和路由组可去看其他大神文章。
路由可看做是路由树中的一个节点,Engine 对象包含一个 addRoute 方法用于添加路由,它会将对应的路径和处理挂接到相应的请求树中,当有URL请求发送到后端,根据请求URL匹配到对应的路由,完成定义好的处理函数。
而路由组就如同是路由的父节点一般,我们可以将拥有共同URL前缀的路由划分为一个路由组。习惯性一对{}
包裹同组的路由,这只是为了看着清晰,你用不用{}
包裹功能上没什么区别。具体使用如下:
go
func main() {
r := gin.Default()
userGroup := r.Group("/user")
{
userGroup.GET("/index", func(c *gin.Context) {...})
userGroup.GET("/login", func(c *gin.Context) {...})
userGroup.POST("/login", func(c *gin.Context) {...})
}
shopGroup := r.Group("/shop")
{
shopGroup.GET("/index", func(c *gin.Context) {...})
shopGroup.GET("/cart", func(c *gin.Context) {...})
shopGroup.POST("/checkout", func(c *gin.Context) {...})
}
r.Run()
}
Gin框架中的路由使用的是httprouter这个库。
gin.Context
这个对象里保存了请求的上下文信息,它是所有请求处理器的入口参数。
go
type HandlerFunc func(*Context)
type Context struct {
...
Request *http.Request // 请求对象
Writer ResponseWriter // 响应对象
Params Params // URL匹配参数
...
Keys map[string]interface{} // 自定义上下文信息
...
}
你可以通过Context对象获取request请求中的上下文信息,Context提供了丰富的方法,比如请求中的URL参数,Header,Cookie,表单数据这些都可调用Context对象中的方法获取,这一系列方法实质是对http.Request对象的包装。
此外,Context给开发者提供了许多种响应形式,JSON,HTML,Yaml等,他会给每一种形式制定单独的渲染器,这些内置的渲染器足以应对绝大多数场景,如果你觉得不够用还可以自定义渲染器。
go
func (c *Context) JSON(code int, obj interface{})
func (c *Context) HTML(code int, obj interface{})
func (c *Context) YAML(code int, obj interface{})
...
// 自定义渲染 func (c *Context) Render(code int, r render.Render)
所有的渲染器最终还是需要调用的Context.Writer(http.ResponseWriter),将响应对象转换成字节流写到套接字中。
下期见兄弟们。