gin框架 | 青训营

112 阅读6分钟

Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍

Go世界里最流行的Web框架Github上有32K+star。 基于httprouter开发的Web框架。 中文文档齐全,简单易用的轻量级框架。

Gin的安装与使用

安装

1.  命令行输入
1.  go get -u github.com/gin-gonic/gin

使用,一个helloworld例子

1.  import (
1.  "net/http"
1.
1.  "github.com/gin-gonic/gin"
1.  )
1.
1.  func main() {
1.  // 1.创建路由
1.  r := gin.Default()
1.  // 2.绑定路由规则,执行的函数
1.  // gin.Context,封装了request和response
1.  r.GET("/", func(c *gin.Context) {
1.  c.String(http.StatusOK, "hello World!")
1.  })
1.  // 3.监听端口,默认在8080
1.  // Run("里面不指定端口号默认为8080")
1.  r.Run(":8000")
1.  }

将上面的代码保存并编译执行,然后使用浏览器打开127.0.0.1:8080/hello就能看到一串JSON字符串。

RESTful API

REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”。

简单来说,REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作。

  • GET用来获取资源
  • POST用来新建资源
  • PUT用来更新资源
  • DELETE用来删除资源。
1.  r.GET("/book", func(c *gin.Context){
1.  c.JSON(200, gin.H{
1.  "method":"GET"
1.  })
1.  })
1.  r.POST("/book",func(c *gin.Context){
1.  c.JSON(200, gin.H{
1.  "method":"POST"
1.  })
1.  })
1.  r.PUT("/book",func(c *gin.Context){
1.  c.JSON(200, gin.H{
1.  "method":"PUT"
1.  })
1.  })
1.  r.DELETE("/book",func(c *gin.Context){
1.  c.JSON(200, gin.H{
1.  "method":"DELETE"
1.  })
1.  })

只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互。

template

Go语言内置了文本模板引擎text/template和用于HTML文档的html/template。它们的作用机制可以简单归纳如下:

  1. 模板文件通常定义为.tmpl和.tpl为后缀(也可以使用其他的后缀),必须使用UTF8编码。
  2. 模板文件中使用{{和}}包裹和标识需要传入的数据。
  3. 传给模板这样的数据就可以通过点号(.)来访问,如果数据是复杂类型的数据,可以通过{ { .FieldName }}来访问它的字段。
  4. 除{{和}}包裹的内容外,其他内容均不做修改原样输出。

HTML渲染

gin框架中使用LoadHTMLGlob() 或者LoadHTMLFiles()方法进行HTML模板渲染

1.  //r.LoadHTMLFiles("templates/posts/index.html", "templates/users/index.html")
1.  r.GET("/posts/index", func(c *gin.Context) {
1.  c.HTML(http.StatusOK, "posts/index.html", gin.H{
1.  "title": "posts/index",
1.  })
1.  })
1.
1.  r.GET("users/index", func(c *gin.Context) {
1.  c.HTML(http.StatusOK, "users/index.html", gin.H{
1.  "title": "users/index",
1.  })
1.  })

静态文件处理、

当我们渲染的HTML文件中引用了静态文件时,我们只需要在渲染页面前调用gin.Static 方法即可

1.  func main() {
1.  r := gin.Default()
1.  r.Static("/static", "./static")
1.  r.LoadHTMLGlob("templates/**/*")
1.  // ...
1.  r.Run(":8080")
1.  }

JSON渲染

1.  func main(){
1.  r := gin.Default()
1.
1.  //加载静态文件
1.  //r.Static("/static","./statics")
1.  r.GET("/someJSON",func(c *gin.Context){
1.  //方式一:自己拼接json
1.  c.JSON(http.StatusOK, gin.H{
1.  "message": "Hello world",
1.  })
1.  })
1.  r.GET("/moreJSON", func(c *gin.Context){
1.  var msg struct{
1.  Name string `json:"user"`
1.  Message string
1.  Age int
1.  }
1.  msg.Name="hhh"
1.  msg.Message="Helloworld!"
1.  msg.Age = 18
1.  c.JSON(http.StatusOK,msg)
1.  })
1.  r.Run(":8080")
1.  }

XML渲染

1.  func main(){
1.  r := gin.Default()
1.
1.  //加载静态文件
1.  //r.Static("/static","./statics")
1.  r.GET("/someXML",func(c *gin.Context){
1.  //方式一:自己拼接json
1.  c.XML(http.StatusOK, gin.H{
1.  "message": "Hello world",
1.  })
1.  })
1.  r.GET("/moreXML", func(c *gin.Context){
1.  type msg struct{
1.  Name string
1.  Message string
1.  Age int
1.  }
1.  var message msg
1.  message.Name="hhh"
1.  message.Message="Helloworld!"
1.  message.Age = 18
1.  c.XML(http.StatusOK,message)
1.  })
1.  r.Run(":8080")
1.  }

除此之外还有YMAL渲染和上边的两种方法的使用方式相差不多

获取path参数

请求的参数通过URL路径传递

1.  func main() {
1.  //Default返回一个默认的路由引擎
1.  r := gin.Default()
1.  r.GET("/user/search/:username/:address", func(c *gin.Context) {
1.  username := c.Param("username")
1.  address := c.Param("address")
1.  //输出json结果给调用方
1.  c.JSON(http.StatusOK, gin.H{
1.  "message": "ok",
1.  "username": username,
1.  "address": address,
1.  })
1.  })
1.
1.  r.Run(":8080")
1.  }

参数绑定

为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryString、form表单、JSON、XML等参数到结构体中。 下面的示例代码演示了 .ShouldBind()强大的功能,它能够基于请求自动提取JSON、form表单和QueryString类型的数据,并把值绑定到指定的结构体对象。

ShouldBind会按照下面的顺序解析请求中的数据完成绑定:

  1. 如果是 GET 请求,只使用 Form 绑定引擎(query)。
  2. 如果是 POST 请求,首先检查 content-type 是否为 JSON 或 XML,然后再使用 Form(form-data)。

重定向

HTTP重定向

HTTP 重定向很容易。 内部、外部重定向均支持。

1.  r.GET("/test", func(c *gin.Context) {
1.  c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
1.  })

路由重定向

路由重定向,使用HandleContext:

1.  r.GET("/test", func(c *gin.Context) {
1.  // 指定重定向的URL
1.  c.Request.URL.Path = "/test2"
1.  r.HandleContext(c)
1.  })
1.  r.GET("/test2", func(c *gin.Context) {
1.  c.JSON(http.StatusOK, gin.H{"hello": "world"})
1.  })

Gin路由

普通路由‘

r.Any("/test", func(c *gin.Context){...})

Any方法可以匹配所有的请求方法

为没有配置处理函数的路由添加处理程序,默认情况下它返回404代码,下面的代码为没有匹配到路由的请求都返回

views/404.html页面。

r.NoRoute(func(c *gin.Context) {
		c.HTML(http.StatusNotFound, "views/404.html", nil)
	})

路由原理

Gin框架中的路由使用的是httprouter这个库。

其基本原理就是构造一个路由地址的前缀树。

中间件

Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。

定义中间件

Gin中的中间件必须是一个gin.HandlerFunc类型

func indexHandler(c *gin.Context) {
   c.JSON(http.StatusOK, gin.H{
      "msg": "index",
   })
}
 
func main(){
   r := gin.Default()
   r.GET("index", indexHandler)
   r.Run()
}

注册中间件

在gin框架中,我们可以为每个路由添加任意数量的中间件。

 r.GET("index",m1,... indexHandler)

c.Next() 调用后续的处理函数

c.Abort() 阻止调用后续的处理函数

//计算执行程序花费的时间
func m1(c *gin.Context){
   start := time.Now()
   c.Next()
   cost := time.Since(start)
   fmt.Println("cost:%v\n",cost)
}
//

gin默认中间件

gin.Default()默认使用了Logger和Recovery中间件,其中:

  • Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
  • Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。

如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。

gin中间件中使用goroutine

当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。