Gin 是使用 Go/golang 语言实现的 HTTP Web 框架。接口简洁,性能极高。
Gin 特性
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello, World")
})
r.Run() // listen and serve on 0.0.0.0:8080
}
路由是一个非常重要的概念,所有的接口都要有路由来进行管理。Gin 的路由支持 GET , POST , PUT , DELETE , PATCH , HEAD , OPTIONS 请求,同时还有一个 Any 函数,可以同时支持以上的所有请求。
路由需要传入两个参数,一个为路径,另一个为路由执行的方法,我们叫做它处理器 Handler ,而且,该参数是可变长参数。也就是说,可以传入多个 handler,形成一条 handler chain 。同时对 handler 该函数有着一些要求,该函数需要传入一个 Gin.Context 指针,同时要通过该指针进行值得处理。
r.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name") //获取路径里name的值
c.String(http.StatusOK, "Hello %s", name)
})
比如:
$ curl http://localhost:9999/user/saber
Hello saber
// 匹配users?name=xxx&role=xxx,role可选
r.GET("/users", func(c *gin.Context) {
name := c.Query("name")
role := c.DefaultQuery("role", "teacher")
c.String(http.StatusOK, "%s is a %s", name, role)
})
r.POST("/form", func(c *gin.Context) {
username := c.PostForm("username")
password := c.DefaultPostForm("password", "000000") // 可设置默认值
c.JSON(http.StatusOK, gin.H{
"username": username,
"password": password,
})
})
也可以使用struct模型绑定来接住:
type UserModel struct {
Email string `form:"email"`
Password string `form:"password"`
PasswordAgain string `form:"password-again"`
}
func UserRegister(context *gin.Context) {
var user model.UserModel
if err := context.ShouldBind(&user); err != nil {
println("err ->", err.Error())
return
}
println("email", user.Email, "password", user.Password, "password again", user.PasswordAgain)
}
做后端开发的人都明白一个道理:永远不要相信前端传过来的数据。所有的数据在进过后端时,务必要进行数据的校验。
在模型中可用 binding 来对数据进行校验。Gin 对于数据校验使用的是 validator.v8 库,该库提供多种校验方法。通过 binding:"" 方式来进行对数据的校验。
type UserModel struct {
Email string `form:"email" binding:"email"`
Password string `form:"password"`
PasswordAgain string `form:"password-again" binding:"eqfield=Password"`
}
r.GET("/redirect", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/index")
})
r.GET("/goindex", func(c *gin.Context) {
c.Request.URL.Path = "/"
r.HandleContext(c)
})
// group routes 分组路由
defaultHandler := func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"path": c.FullPath(),
})
}
// group: v1
v1 := r.Group("/v1")
{
v1.GET("/posts", defaultHandler)
v1.GET("/series", defaultHandler)
}
// group: v2
v2 := r.Group("/v2")
{
v2.GET("/posts", defaultHandler)
v2.GET("/series", defaultHandler)
}
$ curl http://localhost:9999/v1/posts
{"path":"/v1/posts"}
$ curl http://localhost:9999/v2/posts
{"path":"/v2/posts"}
中间件 middleware 在 golang 中是一个很重要的概念,与 java 中拦截器很相似。我们在这里通过 gin 源代码来看看中间件代码使用。
回到main()方法:
router := gin.Default()
这个gin.Default()做了什么?
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
源码中,首先是 New 了一个 engine ,紧接着通过 Use 方法,传入了 Logger() 和 Recovery() ,而 Logger和 Recovery 就是两个中间件。
其中 Logger 是对日志进行记录,而 Recovery 是对有 painc时, 进行 500 的错误处理
查看了源码之后,那么我们也就知道如何使用中间件了。
中间件需要返回 gin.HandlerFunc 函数,所以定义返回函数。
而且 中间件有个 Next 函数,在我们定义的众多中间件,会形成一条中间件链,而通过 Next 函数来对后面的中间件进行执行。
我们来自己定义一个 Logger 日志,新建一个 middleware 文件夹,里面新建 Logger.go,进行我们自定义的日志展示。
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"time"
)
func Logger() gin.HandlerFunc {
return func(context *gin.Context) {
host := context.Request.Host
url := context.Request.URL
method := context.Request.Method
fmt.Printf("%s::%s \t %s \t %s ", time.Now().Format("2006-01-02 15:04:05"), host, url, method)
context.Next()
fmt.Println(context.Writer.Status())
}
}
修改 initRouter 中的 SetupRouter 方法,将我们自定义的中间件进行添加。
router := gin.New()
// 添加自定义的 logger 中间件
router.Use(middleware.Logger(), gin.Recovery())
此时重新启动我们的项目,访问localhost:8080端口,控制台上就会打印出我们新的格式日志。
2019-07-23 18:17:58::localhost:8080 / GET 200
package middleware
import "github.com/gin-gonic/gin"
func Auth() gin.HandlerFunc {
return func(context *gin.Context) {
println("已经授权")
context.Next()
}
}
userRouter.GET("/profile/", middleware.Auth(), handler.UserProfile)
userRouter.POST("/update", middleware.Auth(), handler.UpdateUserProfile)
再次运行项目,当我们对用户详情页进行访问的时候,控制台上会打印出 已经授权 的日志,而访问其他页面则不会出现,说明我们的中间件使用成功。