轻松上手 Go web 框架 Gin | 青训营笔记

447 阅读5分钟

这是我参与「第五届青训营」笔记创作活动的第8天

高性能 web 框架 - Gin

前言:

Golang 的 web 框架选择非常多,从 Java 切换到 Go 的我着实被 Go 的众多 web 框架惊艳到了,直接搜索 Go Web 框架关键字就能搜出五六款不同的框架,属实是激发了我的选择困难症😂

目前流行的 Web 框架有 Gin、Echo、Beego、Iris,各自特点如下:

框架优点缺点
Gin速度快、中间件友好框架比较精简,模块较少
Echo轻量级,路由性能高调试不方便
Beego功能全面,社区良好比较臃肿
Iris完备的MVC支持,社区活跃度高不够稳定

本次青训营课程主要介绍了 Gin 与字节跳动官方出品的 Herzt 框架,今天先来对 Gin 框架做一个快速上手 ...


Gin 简介

image.png

Gin 是用 Golang 编写的 Web 框架,以更好的性能你实现类似 Martini 框架的 API,号称速度比 Martini 快了 40 倍。Gin 封装比较优雅,API 友好,源码注释明确,具有快速灵活、容错方便等特点。

借助框架开发,不仅可以省去很多常用的封装带来的麻烦,也有助于团队的编码风格形成规范。

🎈Gin 中文站点:Gin Web Framework (gin-gonic.com)


第一个 Gin 程序

先从官网的快速入门文档入手,使用 GoLand 创建第一个 Gin 程序 - Hello World

  1. 首先创建 Go 项目,添加 main.go 入口文件,然后在终端中使用下面的指令获取 Gin 依赖:
    $ go get -u github.com/gin-gonic/gin
    

image.png

  1. 将 Gin 引入到代码中:

    import "github.com/gin-gonic/gin"
    
  2. 编辑 main.go 代码:

    package main
    
    import "github.com/gin-gonic/gin"
    
    func main()  {
       server := gin.Default() // 创建服务
       /* 处理请求 */
       server.GET("/hello", func(context *gin.Context) {
          context.JSONP(200, gin.H{"msg": "Hello World !"})
       })
       server.Run() // 监听并在 0.0.0.0:8080 上启动服务
    }
    
  3. GoLand 中右键运行程序,或者使用如下指令运行:

    $ go run main.go
    
  4. 项目启动以后,使用浏览器访问 http://localhost:8080/hello 就可以看到后端传回来的 json 数据了~

    image.png

从上面的流程来看,使用 Golang 编写 web 程序还是非常简单的,尤其是相比较于 Java 的 SpringBoot ,免去了编写配置文件、使用注解处理请求等等繁杂的操作,我们只需要使用 gin.Default() 获取 server 对象,用它就可以处理各种请求。


Restful API

目前在前后端分离的架构中,前后端基本都是通过 Restful API 来进行交互。

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

  • GET - 用来获取资源
  • POST - 用来新建资源
  • PUT - 用来更新资源
  • DELETE - 用来删除资源

Gin 框架对 Restful 风格有着良好的支持,代码十分简单,示例如下:

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    r := gin.Default()
    r.GET("/usr", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"msg": "查询用户信息成功"})
    })
    r.POST("/usr", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"msg": "创建用户信息成功"})
    })
    r.PUT("/usr", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"msg": "更新用户信息成功"})
    })
    r.DELETE("/usr", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"msg": "删除用户信息成功"})
    })
    r.Run()
}

响应页面

Gin 框架的 *gin.Context 实例封装了很多种响应方法 Json、HTML、String 等等。

  • 返回给前端一个页面需要先加载静态页面,Gin 提供了两种方式:

    r.LoadHTMLGlob("templates/*")               // 加载指定目录下的所有页面
    r.LoadHTMLFiles("templates/index.html")     // 加载单个页面
    
  • 调用 context.HTML() 方法返回一个页面给前端,其接受三个参数:状态码、页面地址、数据。

页面响应示例:

编写一个前端页面 index.html,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Gin Demo</title>
</head>
<body>
    <h1>Hello World !</h1>
    <p>
        获取后端传来的数据为:{{.msg}}
    </p>
</body>
</html>

编写后端代码,main.go 文件如下:

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    r := gin.Default()
    /* 加载静态页面 */
    r.LoadHTMLGlob("templates/*")
    /* 响应一个页面给前端 */
    r.GET("/index", func(c *gin.Context) {
       c.HTML(http.StatusOK, "index.html", gin.H{
          "msg": "Golang Gin",
       })
    })
    r.Run()
}

浏览器访问 http://localhost:8080/index 可以看到响应的页面以及后端传过来的数据:

image.png

PS: 如果前端页面引用了静态资源,还可以使用 r.Static() 方法进行加载。


获取请求参数

Gin 获取前端发送过来的参数十分简单。

🎈Get 请求:

Gin 获取 Get 请求发送的参数只要一行代码,支持问号拼接与 Restful 两种格式。

  1. 获取使用拼接字符串方式的 url 参数:
    // url: localhost:8080/usr?id=001&name=jack
    r.GET("/usr", func(c *gin.Context) {
        id := c.Query("id")
        name := c.Query("name")
    })
    
  2. 获取使用 Restful 风格的 url 参数:
    // url: localhost:8080/usr/001/jack
    r.GET("/usr/:id/:name", func(c *gin.Context) {
        id := c.Param("id")
        name := c.Param("name")
    })
    

🎈Post 请求:

前端一般使用 json 格式在 Post 请求中传递参数,Gin 获取 json 数据以后可以使用 Golang 自带的 Json 包进行反序列化操作拿到对应的数据。

r.POST("/usr", func(c *gin.Context) {
    data, _ := c.GetRawData()
    var m map[string]interface{}
    _ = json.Unmarshal(data, &m)
})

路由 Router

Gin 的重定向操作也只需要一行代码就能搞定:

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

访问页面不存在时可以使用 NoRoute 统一跳转至 404 页面:

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

🎈路由组:

在 Gin 框架中提供了一个函数 Group 可以对路由进行分组管理,使用语法如下:

userGroup := r.Group("/usr")
{
    userGroup.GET("/add", func(c *gin.Context) {
      // ...
    })
    userGroup.POST("/login", func(c *gin.Context) {
      // ...
    })
    userGroup.POST("/logout", func(c *gin.Context) {
      // ...
    })
}

自定义中间件

Gin 框架允许在处理请求的过程中加入钩子函数(Hook),也就是中间件,用来预处理一些公共的业务,比如登录授权、验证、分页等等。

Gin 的中间件是 gin.HandlerFunc 类型,示例如下:

func myHandler() (gin.HandlerFunc) {
    return func(c *gin.Context) {
       c.Set("userid", "123")  // 在中间件中保存数据
       c.Next()  // 放行,执行后续逻辑
       c.Abort()  // 阻止调用后续处理的函数
    }
}

在处理请求时使用自定义中间件:

r.GET("/usr", myHandler(), func(c *gin.Context) {
    userid := c.MustGet("userid").(string)  // 获取保存在中间件的数据
    log.Println(userid)
})

🚀【参考】🚀

  1. 青训营直播课程:Go 框架三件套
  2. Go主流框架对比:Gin Echo Beego Iris - 掘金 (juejin.cn)
  3. 快速转型GoWeb开发 | Go语言零基础教程_哔哩哔哩_bilibili
  4. Gin RESTful API_w3cschool
  5. Gin框架(四):路由组使用 | 猿码记 (liuqh.icu)
  6. Gin框架中间件 - RandySun - 博客园 (cnblogs.com)