likes
comments
collection
share

【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习

作者站长头像
站长
· 阅读数 16

虽然对于程序员来说,项目使用何种语言并不是很重要,但笔者实际上更喜欢更具优雅性的Go。如果说Java至少能带来保底的工作,那么Go是个人追求的理想。必要的生存和诗意的生活之间并不冲突。

Gin特性

  • 路由基于基数树,占用极小内存,无反射,API性能可预测
  • 有一系列中间件支持
  • 会捕获panic并修复,不用担心程序crash
  • 会解析和验证请求的json
  • 路由分组,更好地管理路由
  • 提供收集错误的便捷方式,后期可以利用一个中间件将错误信息写入日志文件、数据库等
  • 内置API,支持渲染JSON, XML 和 HTML
  • 可以方便地自定义中间件

快速上手

体验项目运行只要五步

  • 点击File-new-Project,新建一个项目
    • Linux环境下也可以直接自己mkdir,再自己新建go.mod、main.go等文件
  • 在终端当前路径下输入
go get -u github.com/gin-gonic/gin
  • 新建main.go文件,导入示例代码:
    • 可以直接把相应项目代码复制粘贴到main.go中,
    • 也可以通过在终端通过curl导入
curl https://raw.githubusercontent.com/gin-gonic/examples/master/basic/main.go > main.go

此时IDE会自动导入代码中提到的包,如果所用的编辑器不支持自动导入,那么就手动导入所需包:

import "github.com/gin-gonic/gin"
import "net/http"
  • 运行
    • 点击func main()左边的绿色三角以执行go build and go run 命令
    • 也可以在终端键入go run main.go来运行
  • 测试
    • 对于简单的get请求,可以直接在浏览器中输入网址+请求参数
    • 对于稍微复杂一些的接口测试,图形界面下可以用Postman/apipost/apifox等
    • 命令行下可以考虑curl这个工具

示例代码分析

以下代码是官方文档里提到的https://raw.githubusercontent.com/gin-gonic/examples/master/basic/main.go的代码,中文是我加的注释,简略说明了代码的作用。

package main

import (
   "net/http"

   "github.com/gin-gonic/gin"
)

//用一个map来存储key-value信息,在示例代码中key是用户名,value可被对应用户设定为任意值,curl的example中刚好设定为了密码值
var db = make(map[string]string)

//设置并返回路由
func setupRouter() *gin.Engine {
   // Disable Console Color
   // gin.DisableConsoleColor()
   r := gin.Default()

   // Ping test
   r.GET("/ping", func(c *gin.Context) {
      c.String(http.StatusOK, "pong")
   })

//查询相应的信息(所有用户都可以通过get访问到)
   // Get user value
   r.GET("/user/:name", func(c *gin.Context) {
      user := c.Params.ByName("name")
      value, ok := db[user]
      if ok {
         c.JSON(http.StatusOK, gin.H{"user": user, "value": value})
      } else {
         c.JSON(http.StatusOK, gin.H{"user": user, "status": "no value"})
      }
   })

   // Authorized group (uses gin.BasicAuth() middleware)
   // Same than:
   // authorized := r.Group("/")
   // authorized.Use(gin.BasicAuth(gin.Credentials{
   //   "foo":  "bar",
   //   "manu": "123",
   //}))
   
   //设置分组路由,批量设置身份账号信息
   authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
      "foo":  "bar", // user:foo password:bar
      "manu": "123", // user:manu password:123
   }))

   /* example curl for /admin with basicauth header
      Zm9vOmJhcg== is base64("foo:bar")

      curl -X POST \
      http://localhost:8080/admin \
      -H 'authorization: Basic Zm9vOmJhcg==' \
      -H 'content-type: application/json' \
      -d '{"value":"bar"}'
   */
   
   //在上述认证名单内的账号可以绑定对应的value信息
   authorized.POST("admin", func(c *gin.Context) {
      user := c.MustGet(gin.AuthUserKey).(string)

      // Parse JSON
      var json struct {
         Value string `json:"value" binding:"required"`
      }

      if c.Bind(&json) == nil {
         db[user] = json.Value
         c.JSON(http.StatusOK, gin.H{"status": "ok"})
      }
   })

   return r
}

func main() {
   r := setupRouter()
   // Listen and Server in 0.0.0.0:8080
   r.Run(":8080")
}

如何理解这里的设置路由呢?

其实它和计网所说的实体的“路由器”不太一样,是一个虚拟的概念。它更强调内容的分发:对于不同的请求,返回不同的值。

如何理解分组路由呢?

它是一种批量操作的概念,在这里用于批量鉴权认证,也可以用于在路径前缀一致的情况下成批写接口:

参考这篇文章 Golang Gin 实战(七)| 分组路由源代码分析

比如:

	v1Group := r.Group("/v1")
	{
		v1Group.GET("/users", func(c *gin.Context) {
			c.String(200, "/v1/users")
		})
		v1Group.GET("/products", func(c *gin.Context) {
			c.String(200, "/v1/products")
		})
	}

关于curl与apifox使用转换的小技巧

在示例代码的注释中,提到了可以使用curl的一个小例子。 在apifox中,我们可以按图所示快速导入curl:

【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习

【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习

Postman和apipost的入口笔者还没找,想来应该是大同小异的,需要用到的时候查阅帮助文档即可。 示例代码中的curl example是这样的:

   /* example curl for /admin with basicauth header
      Zm9vOmJhcg== is base64("foo:bar")

      curl -X POST \
      http://localhost:8080/admin \
      -H 'authorization: Basic Zm9vOmJhcg==' \
      -H 'content-type: application/json' \
      -d '{"value":"bar"}'
   */

可以看到:

【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习

【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习 -H 对应headers,-d是在body中的。

那如何举一反三呢?比如变为请求"manu": "123"

注意观察其中的curl格式: Zm9vOmJhcg== 是foo:bar经过base64编码后的结果,所以我们可以使用一些base64的编解码小工具,获取到manu:123的编码结果为:bWFudToxMjM=。(需要注意的是待编码元素没有加上"",笔者加上了之后是错误的,不知道是操作系统平台的解析问题、还是注释的描述容易引起误会)。用其替换掉-H 对应的编码串。

可以看到也是请求成功。 【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习

但是要注意一个问题:这本质上是一个鉴权的操作,前面的foo:barmanu:123之所以可行,是因为它们在认证账号名单内,而且它们只能修改自己对应的值:

authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
   "foo":  "bar", // user:foo password:bar
   "manu": "123", // user:manu password:123
}))

所以如果要新增修改对象,首先要添加相应的对象,否则会显示没有权限。 【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习

至此,示例代码就学习完毕了。接下来笔者会去学习一下其他示例项目、了解更多中间件。

参考资料