安装
1 2 |
go get -u -v github.com/gin-gonic/gin |
快速入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() // listen and serve on 0.0.0.0:8080 } # 访问 http://192.168.31.105:8080/ping # 返回 # { # message: "pong" # } |
实现无缝重启、停机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 使用 fvbock/endless, 不兼容windows package main import ( "github.com/fvbock/endless" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) endless.ListenAndServe("0.0.0.0:8080", r) } |
GET, POST, PUT, PATCH, DELETE and OPTIONS
1 2 3 4 5 6 7 8 |
router.GET("/someGet", getting) router.POST("/somePost", posting) router.PUT("/somePut", putting) router.DELETE("/someDelete", deleting) router.PATCH("/somePatch", patching) router.HEAD("/someHead", head) router.OPTIONS("/someOptions", options) |
带参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { router := gin.Default() router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) router.Run(":8080") } |
query 参数
1 2 3 4 5 6 7 8 9 10 11 |
router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") lastname := c.DefaultQuery("lastname", "Guest") //可设置默认值 // lastname := c.Query("lastname") // 是 c.Request.URL.Query().Get("lastname") 的简写 message := name + " - " + lastname + " is " + action c.String(http.StatusOK, message) }) |
post请求
1 2 3 4 5 6 7 8 9 10 11 12 |
router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("message") nick := c.DefaultPostForm("nick", "anonymous") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) |
上传文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
router.POST("/upload", func(c *gin.Context) { // single file file, _ := c.FormFile("file") log.Println(file.Filename) // Upload the file to specific dst. c.SaveUploadedFile(file, file.Filename) // 保存 // file.Filename 是保存路径。保存在当前目录下的该文件名 // 也可以使用绝对路径 c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) |
分组路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// Simple group: v1 v1 := router.Group("/v1") { v1.POST("/login", func(c *gin.Context) { c.String(http.StatusOK, "v1.login") }) v1.POST("/submit", func(c *gin.Context) { c.String(http.StatusOK, "v1.submit") }) v1.POST("/read", func(c *gin.Context) { c.String(http.StatusOK, "v1.read") }) } // Simple group: v2 v2 := router.Group("/v2") { v2.POST("/login", func(c *gin.Context) { c.String(http.StatusOK, "v2.login") }) v2.POST("/submit", func(c *gin.Context) { c.String(http.StatusOK, "v2.submit") }) v2.POST("/read", func(c *gin.Context) { c.String(http.StatusOK, "v2.read") }) } |
- 访问
192.168.31.105:8080/v1/submit
返回v1.submit
- 访问
192.168.31.105:8080/v2/submit
返回v2.submit
使用中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package main import ( "fmt" "github.com/gin-gonic/gin" "log" "net/http" ) func main() { r := gin.New() // 全局中间件 r.Use(gin.Logger()) r.Use(gin.Recovery()) r.Use(func(c *gin.Context) { log.Println("mid before") c.Next() log.Println("mid after") }) r.GET("/echo", func(c *gin.Context) { fmt.Println("echo 1") }, func(c *gin.Context) { fmt.Println("echo 2") }) // 组中间件 v1 := r.Group("/v1") v1.Use(func(c *gin.Context) { log.Println("group mid before") c.Next() log.Println("group mid after") }) { v1.POST("/login", func(c *gin.Context) { c.String(http.StatusOK, "v1.login") }) v1.POST("/submit", func(c *gin.Context) { c.String(http.StatusOK, "v1.submit") }) v1.POST("/read", func(c *gin.Context) { c.String(http.StatusOK, "v1.read") }) } r.Run(":8080") } |
请求日志记录文件
1 2 3 4 5 6 |
# 初始化gin框架前,先进行设置 gin.DisableConsoleColor() f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) |
绑定参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// 绑定json // Example for binding JSON ({"user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login if err := c.ShouldBindJSON(&json); err == nil { fmt.Println(json) if json.User == "manu" && json.Password == "123" { c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) } else { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) } } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) // 绑定form表单 // Example for binding a HTML form (user=manu&password=123) router.POST("/loginForm", func(c *gin.Context) { var form Login // This will infer what binder to use depending on the content-type header. if err := c.ShouldBind(&form); err == nil { fmt.Println(form) if form.User == "manu" && form.Password == "123" { c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) } else { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) } } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) |
跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# http 重定向 r.GET("/test", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") }) # 路由重定向 r.GET("/test", func(c *gin.Context) { c.Request.URL.Path = "/test2" r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { c.JSON(200, gin.H{"hello": "world"}) }) |