Gin笔记
参考文档
创建Engine
engine1 := gin.Default()
engine2 := gin.New()
gin.Default()
和 gin.New()
的区别在于 gin.Default() 也使用 gin.New() 创建engine实例,但是会默认使用 Logger 和 Recovery 中间件。
- Logger 是负责进行打印并输出日志的中间件,方便开发者进行程序调试;
- Recovery 中间件的作用是如果程序执行过程中遇到 panic 中断了服务,则 Recovery 会恢复程序执行,并返回服务器500内部错误。通常情况下,我们使用默认的 gin.Default() 创建 Engine 实例。
处理HTTP请求方式
Handle
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes
Handle样例(部分代码):
func main() {
engine := gin.Default()
// GET
// http://localhost:8080/handle?name=Jake
engine.Handle("GET", "/handle", handleGET)
// POST
// http://localhost:8080/handle
engine.Handle("POST", "/handle", handlePOST)
err := engine.Run()
if err != nil {
fmt.Printf("engine Run failed: %v", err.Error())
}
}
Router
func main() {
engine := gin.Default()
// GET
// http://localhost:8080/router?name=Jake
engine.GET("/router", routerGET)
// POST
// http://localhost:8080/router
engine.POST("/router", routerPOST)
err := engine.Run()
if err != nil {
fmt.Printf("engine Run failed: %v", err.Error())
}
}
表单实体绑定
Gin框架提供数据结构体和表单提交数据绑定的功能,提高表单数据获取的效率。结构体加标签
func main() {
engine := gin.Default()
// GET
engine.GET("/formbind", func(c *gin.Context) {
var stu Student
if err := c.ShouldBindQuery(&stu); err != nil {
log.Fatalln(err.Error())
return
}
c.String(http.StatusOK, "Hello %s", stu.Name)
})
// POST
engine.POST("/formbind", func(c *gin.Context) {
var stu Student
// JSON 格式
if err := c.BindJSON(&stu); err != nil {
log.Fatalln(err.Error())
return
}
c.String(http.StatusOK, "姓名: %s\n性别: %s\n年龄: %d", stu.Name, stu.Sex, stu.Age)
})
engine.Run(":8080")
}
type Student struct {
Name string `form:"name"`
Sex string `form:"sex"`
Age int `form:"age"`
}
返回数据格式
[]byte
// []byte
engine.GET("/response/byte", func(c *gin.Context) {
c.Writer.Write([]byte(fmt.Sprintf("code: %d\nmessage: %s\ndata: 请求路径 %s", 200, "OK", c.FullPath())))
})
string
// string
engine.GET("/response/string", func(c *gin.Context) {
c.String(http.StatusOK, fmt.Sprintf("code: %d\nmessage: %s\ndata: 请求路径 %s", 200, "OK", c.FullPath()))
})
JSON
-
map 类型转换为 JSON
// JSON map engine.GET("/response/json/map", func(c *gin.Context) { // type H map[string]interface{} //c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, map[string]interface{} { "code": 200, "message": "OK", "data": "请求路径" + c.FullPath(), }) })
-
结构体类型转换为 JSON
// JSON struct engine.GET("/response/json/struct", func(c *gin.Context) { res := Response{ Code: 200, Message: "OK", Data: "请求路径" + c.FullPath(), } c.JSON(http.StatusOK, &res) })
HTML模板渲染
官方文档样例:https://gin-gonic.com/zh-cn/docs/examples/html-rendering/
文件上传
- 单个文件上传:https://gin-gonic.com/zh-cn/docs/examples/upload-file/single-file/
- 多个文件上传:https://gin-gonic.com/zh-cn/docs/examples/upload-file/multiple-file/
HTTP重定向
HTTP 重定向很容易。 内部、外部重定向均支持。
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://jakelin.cn/")
})
// 通过 POST 方法进行 HTTP 重定向
r.POST("/test", func(c *gin.Context) {
c.Redirect(http.StatusFound, "/foo")
})
路由重定向,使用 HandleContext
:
r.GET("/test", func(c *gin.Context) {
// 指定重定向的URL
c.Request.URL.Path = "/test2"
r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
路由组
Gin框架中的路由使用的是 httprouter 这个库。其基本原理就是构造一个路由地址的前缀树。
func main() {
router := gin.Default()
// 简单的路由组: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// 简单的路由组: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
router.Run(":8080")
}
中间件
自定义中间件
两条标志:
- func 函数
- 返回值类型为
gin.HandlerFunc
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
// 请求前处理操作
fmt.Println("请求前处理操作: path =", c.FullPath())
// func (c *Context) Next() 将中间件执行一分为二
c.Next()
// 请求后处理操作
fmt.Println("请求后处理操作: status=", c.Writer.Status())
}
}
注册中间件
- 注册全局中间件
- 每个路由注册任意个中间件
- 路由组注册中间件
- 嵌套路由组注册中间件
func main() {
// 新建一个没有任何默认中间件的路由
r := gin.New()
// 1、全局中间件
// Logger 中间件将日志写入 gin.DefaultWriter,即使你将 GIN_MODE 设置为 release。
// By default gin.DefaultWriter = os.Stdout
r.Use(gin.Logger())
// Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500。
r.Use(gin.Recovery())
// 2、每个路由添加任意数量的中间件。
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
// 认证路由组
// authorized := r.Group("/", AuthRequired())
// 和使用以下两行代码的效果完全一样:
authorized := r.Group("/")
// 3、路由组中间件! 在此例中,我们在 "authorized" 路由组中使用自定义创建的
// AuthRequired() 中间件
authorized.Use(AuthRequired())
{
authorized.POST("/login", loginEndpoint)
authorized.POST("/submit", submitEndpoint)
authorized.POST("/read", readEndpoint)
// 4、嵌套路由组添加中间件
testing := authorized.Group("testing")
testing.GET("/analytics", analyticsEndpoint)
}
// 监听并在 0.0.0.0:8080 上启动服务
r.Run(":8080")
}
中间件注意事项
-
gin.Default()
默认使用了Logger
和Recovery
中间件,其中:Logger
中间件将日志写入gin.DefaultWriter
,即使配置了GIN_MODE=release
。Recovery
中间件会recover任何panic
。如果有panic的话,会写入500响应码。
-
gin 中间件中使用 goroutine
当在 中间件 或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(
c.Copy()
)。 -
注册多个中间件,中间件的执行是递归嵌套的(根据注册顺序)