Loading

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/

文件上传

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")
}

中间件

自定义中间件

两条标志:

  1. func 函数
  2. 返回值类型为 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() 默认使用了 LoggerRecovery 中间件,其中:

    • Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release
    • Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。
  • gin 中间件中使用 goroutine

    当在 中间件 或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。

  • 注册多个中间件,中间件的执行是递归嵌套的(根据注册顺序)

posted @ 2021-11-25 19:02  JakeLin  阅读(173)  评论(0编辑  收藏  举报