轻量级go语言web框架gin

gin是go语言环境下的一个web框架, 它类似于Martini, 官方声称它比Martini有更好的性能, 比Martini快40倍, Ohhhh….看着不错的样子, 所以就想记录一下gin的学习. gin的github代码在这里: gin源码. gin的效率获得如此突飞猛进, 得益于另一个开源项目httprouter, 项目地址: httprouter源码. 下面主要记录一下gin的使用.

1. 安装gin

使用命令go get github.com/gin-gonic/gin就可以. 我们使用gin的时候引入相应的包就OK

2. 使用方法

1)  一种最简单的使用GET/POST方法

gin服务端代码是:

客户端代码是:

在服务端, 实例化了一个router, 然后使用GET和POST方法分别注册了两个服务, 当我们使用HTTP GET方法的时候会使用GET注册的函数, 如果使用HTTP POST的方法, 那么会使用POST注册的函数.

gin支持所有的HTTP的方法例如: GET, POST, PUT, PATCH, DELETE 和 OPTIONS等. 看客户端中的代码, 当调用http.Get("http://0.0.0.0:8888/test1")的时候, 服务端接收到请求, 并根据/test1将请求路由到func1函数进行 处理. 同理, 调用http.Post("http://0.0.0.0:8888/test2", "",strings.NewReader(""))时候, 会使用func2函数处理. 在func1和func2中, 使用gin.Context填充了一个String的回复. 当然也支持JSON, XML, HTML等其他一些格式数据. 当执行c.String或者c.JSON时, 相当于向http的回复缓冲区写入了 一些数据.

最后调用router.Run(“:8888”)开始进行监听,Run的核心代码是:

其本质就是http.ListenAndServe(addr, engine). 
注意: helpRead函数是用于读取response的Body的函数, 你可以自己定义, 本文中此函数定义为:

2) 传递参数

传递参数有几种方法, 对应到gin使用几种不同的方式来解析.

第一种: 使用gin.Context中的Param方法解析

对应的服务端代码为:

客户端测试代码是:

注意上面定义参数的方法有两个辅助符号: ‘:’和’*’.

如果使用’:’参数方法, 那么这个参数是必须要匹配的, 例如上面的router.GET(“/test3/:name/:passwd”, func3), 当请求URL是 类似于http://0.0.0.0:8888/test3/name=TAO/passwd=123这样的参会被匹配, 如果是http://0.0.0.0:8888/test3/name=TAO 或者http://0.0.0.0:8888/test3/passwd=123是不能匹配的.

但是如果使用’*‘参数, 那么这个参数是可选的. router.GET(“/test5/:name/*passwd”, func5) 可以匹配http://0.0.0.0:8888/test5/name=TAO/passwd=789, 也可以匹配http://0.0.0.0:8888/test5/name=TAO/.

需要注意的一点是, 下面这个URL是不是能够 匹配呢? http://0.0.0.0:8888/test5/name=TAO, 注意TAO后面没有’/’, 这个其实就要看有没有一个路由是到http://0.0.0.0:8888/test5/name=TAO路径的, 如果有, 那么指定的那个函数进行处理, 如果没有http://0.0.0.0:8888/test5/name=TAO会被重定向到http://0.0.0.0:8888/test5/name=TAO/, 然后被当前注册的函数进行处理.

第二种: 使用gin.Context中的Query方法解析

这个类似于正常的URL中的参数传递, 先看服务端代码:

客户端测试代码是:

这种方法的参数也是接在URL后面, 形如http://0.0.0.0:8888/test6?name=BBB&passwd=CCC. 服务器可以使用name := c.Query(“name”)这种 方法来解析参数.

第三种: 使用gin.Context中的PostForm方法解析

我们需要将参数放在请求的Body中传递, 而不是URL中. 先看服务端代码:

客户端代码是:

由于我们使用了request Body, 那么就需要指定Body中数据的形式, 此处是form格式, 即application/x-www-form-urlencoded. 常见的几种http提交数据方式有: application/x-www-form-urlencoded; multipart/form-data; application/json; text/xml. 具体使用请google.
在服务端, 使用message := c.PostForm(“msg”)方法解析参数, 然后进行处理.

3) 传输文件

下面测试从client传输文件到server. 传输文件需要使用multipart/form-data格式的数据, 所有需要设定Post的类型是multipart/form-data. 
首先看服务端代码:

客户端代码是:

首先客户端本地需要有一张”images.png”图片, 同时需要创建一个Form, 并将field-name命名为”uploadFile”, file-name命名为”images.png”. 在服务端, 通过”uploadFile”可以得到文件信息. 客户端继续将图片数据copy到创建好的Form中, 将数据数据Post出去, 注意数据的类型指定! 在服务端, 通过file, header , err := c.Request.FormFile(“uploadFile”)获得文件信息, file中就是文件数据, 将其拷贝到本地文件, 完成文件传输.

4) binding数据

gin内置了几种数据的绑定例如JSON, XML等. 简单来说, 即根据Body数据类型, 将数据赋值到指定的结构体变量中. (类似于序列化和反序列化) 
看服务端代码:

客户端代码:

客户端发送请求, 在服务端可以直接使用c.BindJSON绑定到Json结构体上. 或者使用BindWith函数也可以, 但是需要指定绑定的数据类型, 例如JSON, XML, HTML等. Bind*函数的本质是读取request中的body数据, 拿BindJSON为例, 其核心代码是:

5)  router group

router group是为了方便前缀相同的URL的管理, 其基本用法如下. 
首先看服务端代码:

客户端测试代码:

在服务端代码中, 首先创建了一个组group1 := router.Group(“/g1”), 并在这个组下注册了两个服务, group1.GET(“/read1”, func10) 和group1.GET(“/read2”, func11), 那么当使用http://0.0.0.0:8888/g1/read1和http://0.0.0.0:8888/g1/read2访问时, 是可以路由 到上面注册的位置的. 同理对于group2 := router.Group(“/g2”)也是一样的.

6) 静态文件服务

可以向客户端展示本地的一些文件信息, 例如显示某路径下地文件. 服务端代码是:

首先你需要在服务器的路径下创建一个assert文件夹, 并且放入1.png文件. 如果已经存在, 请忽略. 
测试代码: 请在浏览器中输入0.0.0.0:8888/showDir, 显示的是服务器当前路径下地文件信息:

输入0.0.0.0:8888/files, 显示的是/bin目录下地文件信息:

输入0.0.0.0:8888/image, 显示的是服务器下地./assets/1.png图片:

7) 加载模板templates

gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据. 
看服务端代码:

客户端测试代码是:

在服务端, 我们需要加载需要的templates, 这里有两种方法: 第一种使用LoadHTMLGlob加载所有的正则匹配的模板, 本例中使用的是*, 即匹配所有文件, 所以加载的是 templates文件夹下所有的模板. 第二种使用LoadHTMLFiles加载指定文件. 在本例服务器路径下有一个templates目录, 下面有一个index.tmpl模板, 模板的 内容是:

当客户端请求/index时, 服务器使用这个模板, 并填充相应的参数, 此处参数只有title, 然后将HTML数据返回给客户端. 
你也可以在浏览器请求0.0.0.0:8888/index, 效果如下图所示:

8) 重定向

重定向相对比较简单, 服务端代码是:

客户端测试代码是:

当我们请求http://0.0.0.0:8888/redirect的时候, 会重定向到http://shanshanpt.github.io/这个站点.

9)  使用middleware

这里使用了两个例子, 一个是logger, 另一个是BasiAuth, 具体看服务器代码:

客户端测试代码是:

服务端使用Use方法导入middleware, 当请求/logger来到的时候, 会执行Logger(), 并且我们知道在GET注册的时候, 同时注册了匿名函数, 所有请看Logger函数中存在一个c.Next()的用法, 它是取出所有的注册的函数都执行一遍, 然后再回到本函数中, 所以, 本例中相当于是先执行了 c.Next()即注册的匿名函数, 然后回到本函数继续执行. 所以本例的Print的输出顺序是: 
log.Println(example) 
log.Print(latency) 
log.Println(status) 
如果将c.Next()放在log.Print(latency)后面, 那么log.Println(example)和log.Print(latency)执行的顺序就调换了. 所以一切都取决于c.Next()执行的位置. c.Next()的核心代码如下:

它其实是执行了后面所有的handlers. 
关于使用gin.BasicAuth() middleware, 可以直接使用一个router group进行处理, 本质和logger一样.

10) 绑定http server

之前所有的测试中, 我们都是使用router.Run(":8888")开始执行监听, 其实还有两种方法:

 

3. gin项目GitHub地址: https://github.com/gin-gonic/gin 

 

源文章:http://www.okyes.me/2016/05/03/go-gin.html

拓展阅读:

http://www.itfanr.cc/2017/07/30/golang-web-framework-gin/