【Go】HTTP框架Gin学习与应用(一)项目环境搭建与示例代码学习
虽然对于程序员来说,项目使用何种语言并不是很重要,但笔者实际上更喜欢更具优雅性的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:
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"}'
*/
可以看到:
-H 对应headers,-d是在body中的。
那如何举一反三呢?比如变为请求"manu": "123"
。
注意观察其中的curl格式:
Zm9vOmJhcg== 是foo:bar经过base64编码后的结果,所以我们可以使用一些base64的编解码小工具,获取到manu:123
的编码结果为:bWFudToxMjM=。(需要注意的是待编码元素没有加上"",笔者加上了之后是错误的,不知道是操作系统平台的解析问题、还是注释的描述容易引起误会)。用其替换掉-H 对应的编码串。
可以看到也是请求成功。
但是要注意一个问题:这本质上是一个鉴权的操作,前面的foo:bar
和manu:123
之所以可行,是因为它们在认证账号名单内,而且它们只能修改自己对应的值:
authorized := r.Group("/", gin.BasicAuth(gin.Accounts{
"foo": "bar", // user:foo password:bar
"manu": "123", // user:manu password:123
}))
所以如果要新增修改对象,首先要添加相应的对象,否则会显示没有权限。
至此,示例代码就学习完毕了。接下来笔者会去学习一下其他示例项目、了解更多中间件。
参考资料
转载自:https://juejin.cn/post/7218482973980852285