快速入门

第一个demo

  1. func main() {
  2. r := gin.Default()
  3. r.GET("/ping", func(c *gin.Context) {
  4. c.JSON(200, gin.H{
  5. "msg": "pong",
  6. })
  7. })
  8. r.Run(":8777")
  9. }

使用get、post、put等http方法

  1. func main() {
  2. // 使用默认中间件创建一个gin路由器
  3. // logger and recovery (crash-free) 中间件
  4. router := gin.Default()
  5. router.GET("/someGet", getting)
  6. router.POST("/somePost", posting)
  7. router.PUT("/somePut", putting)
  8. router.DELETE("/someDelete", deleting)
  9. router.PATCH("/somePatch", patching)
  10. router.HEAD("/someHead", head)
  11. router.OPTIONS("/someOptions", options)
  12. // 默认启动的是 8080端口,也可以自己定义启动端口
  13. router.Run()
  14. // router.Run(":3000") for a hard coded port
  15. }

URL和路由分组

路由分组

  1. func main() {
  2. router := gin.Default()
  3. // Simple group: v1
  4. v1 := router.Group("/v1")
  5. {
  6. v1.POST("/login", loginEndpoint)
  7. v1.POST("/submit", submitEndpoint)
  8. v1.POST("/read", readEndpoint)
  9. }
  10. // Simple group: v2
  11. v2 := router.Group("/v2")
  12. {
  13. v2.POST("/login", loginEndpoint)
  14. v2.POST("/submit", submitEndpoint)
  15. v2.POST("/read", readEndpoint)
  16. }
  17. router.Run(":8777")
  18. }

带参数的url

  1. func main() {
  2. r := gin.Default()
  3. goodsGroup := r.Group("/goods")
  4. {
  5. goodsGroup.GET("", goodsList)
  6. goodsGroup.GET("/:id/:action", goodsDetail)
  7. //goodsGroup.GET("/:id/*action", goodsDetail)
  8. goodsGroup.POST("", createGoods)
  9. }
  10. r.Run(":8777")
  11. }
  12. func goodsList(c *gin.Context) {
  13. c.JSON(http.StatusOK, gin.H{
  14. "name": "list",
  15. })
  16. }
  17. func goodsDetail(c *gin.Context) {
  18. id := c.Param("id")
  19. action := c.Param("action")
  20. c.JSON(http.StatusOK, gin.H{
  21. "id": id,
  22. "action": action,
  23. })
  24. }
  25. func createGoods(c *gin.Context) {
  26. }

获取路由分组的参数

  1. type Person struct {
  2. ID int `uri:"id" binding:"required"`
  3. Name string `uri:"name" binding:"required"`
  4. }
  5. func main() {
  6. r := gin.Default()
  7. r.GET("/:name/:id", func(c *gin.Context) {
  8. var person Person
  9. if err := c.ShouldBindUri(&person); err != nil {
  10. c.Status(404)
  11. return
  12. }
  13. c.JSON(http.StatusOK, gin.H{
  14. "name": person.Name,
  15. "id": person.ID,
  16. })
  17. })
  18. r.Run(":8777")
  19. }

获取参数

获取get /post参数

  1. func main() {
  2. r := gin.Default()
  3. r.GET("/welcome", welcome)
  4. r.POST("/formPost", formPost)
  5. r.Run(":8777")
  6. }
  7. func welcome(c *gin.Context) {
  8. firstname := c.DefaultQuery("first", "lcd")
  9. lastname := c.DefaultQuery("last", "qq")
  10. c.JSON(http.StatusOK, gin.H{
  11. "f": firstname,
  12. "l": lastname,
  13. })
  14. }
  15. func formPost(c *gin.Context) {
  16. msg := c.PostForm("msg")
  17. nick := c.DefaultPostForm("nick", "anonymous")
  18. c.JSON(http.StatusOK, gin.H{
  19. "msg": msg,
  20. "nick": nick,
  21. })
  22. }

JSON、ProtoBuf 渲染

输出json和protobuf

  1. syntax = "proto3";
  2. option go_package = ".;proto";
  3. message Teacher {
  4. string name = 1;
  5. repeated string course = 2;
  6. }
  1. func main() {
  2. r := gin.Default()
  3. // gin.H is a shortcut for map[string]interface{}
  4. r.GET("/someJSON", func(c *gin.Context) {
  5. c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
  6. })
  7. r.GET("/moreJSON", func(c *gin.Context) {
  8. // You also can use a struct
  9. var msg struct {
  10. Name string `json:"user"`
  11. Message string
  12. Number int
  13. }
  14. msg.Name = "Lena"
  15. msg.Message = "hey"
  16. msg.Number = 123
  17. // Note that msg.Name becomes "user" in the JSON
  18. // Will output : {"user": "Lena", "Message": "hey", "Number": 123}
  19. c.JSON(http.StatusOK, msg)
  20. })
  21. r.GET("/someProtoBuf", func(c *gin.Context) {
  22. courses := []string{"python", "django", "go"}
  23. // The specific definition of protobuf is written in the testdata/protoexample file.
  24. data := &proto.Teacher{
  25. Name: "lll",
  26. Course: courses,
  27. }
  28. // Note that data becomes binary data in the response
  29. // Will output protoexample.Test protobuf serialized data
  30. c.ProtoBuf(http.StatusOK, data)
  31. })
  32. r.Run(":8777")
  33. }

pureJSON

通常情况下,JSON会将特殊的HTML字符替换为对应的unicode字符,比如<替换为\u003c,如果想原样输出html,则使用PureJSON
  1. func main() {
  2. r := gin.Default()
  3. // Serves unicode entities
  4. r.GET("/json", func(c *gin.Context) {
  5. c.JSON(200, gin.H{
  6. "html": "<b>Hello, world!</b>",
  7. })
  8. })
  9. // Serves literal characters
  10. r.GET("/purejson", func(c *gin.Context) {
  11. c.PureJSON(200, gin.H{
  12. "html": "<b>Hello, world!</b>",
  13. })
  14. })
  15. r.Run(":8777")
  16. }

表单验证

表单的基本验证(登录注册)

Gin使用 go-playground/validator 验证参数,查看完整文档
  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "reflect"
  6. "strings"
  7. "github.com/go-playground/locales/en"
  8. ut "github.com/go-playground/universal-translator"
  9. en_translations "github.com/go-playground/validator/v10/translations/en"
  10. zh_translations "github.com/go-playground/validator/v10/translations/zh"
  11. "github.com/go-playground/locales/zh"
  12. "github.com/gin-gonic/gin/binding"
  13. "github.com/go-playground/validator/v10"
  14. "github.com/gin-gonic/gin"
  15. )
  16. var trans ut.Translator
  17. type Login struct {
  18. User string ` json:"user" binding:"required,min=3" `
  19. Password string ` json:"password" binding:"required"`
  20. }
  21. type SignUp struct {
  22. Age uint8 `json:"age" binding:"gte=1,lte=130"`
  23. Name string `json:"name" binding:"required"`
  24. Email string `json:"email" binding:"required,email"`
  25. Password string `json:"password" binding:"required"`
  26. RePassword string `json:"re_password" binding:"required,eqfield=Password"`
  27. }
  28. func RemoveTopStruct(fields map[string]string) map[string]string {
  29. rsp := map[string]string{}
  30. for field, err := range fields {
  31. rsp[field[strings.Index(field, ".")+1:]] = err
  32. }
  33. return rsp
  34. }
  35. func InitTrans(locale string) (err error) {
  36. if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
  37. v.RegisterTagNameFunc(func(field reflect.StructField) string {
  38. name := strings.SplitN(field.Tag.Get("json"), ",", 2)[0]
  39. if name == "-" {
  40. return ""
  41. }
  42. return name
  43. })
  44. zhT := zh.New()
  45. enT := en.New()
  46. uni := ut.New(enT, zhT, enT)
  47. trans, ok = uni.GetTranslator(locale)
  48. if !ok {
  49. return fmt.Errorf("uni.GetTranslator(%s)", locale)
  50. }
  51. switch locale {
  52. case "en":
  53. en_translations.RegisterDefaultTranslations(v, trans)
  54. case "zh":
  55. zh_translations.RegisterDefaultTranslations(v, trans)
  56. default:
  57. en_translations.RegisterDefaultTranslations(v, trans)
  58. }
  59. return
  60. }
  61. return
  62. }
  63. func main() {
  64. if err := InitTrans("zh"); err != nil {
  65. fmt.Println("初始化翻译器错误")
  66. return
  67. }
  68. r := gin.Default()
  69. r.POST("/loginJSON", func(c *gin.Context) {
  70. var login Login
  71. if err := c.ShouldBind(&login); err != nil {
  72. fmt.Println(err.Error())
  73. c.JSON(http.StatusBadRequest, gin.H{
  74. "error": err.Error(),
  75. })
  76. return
  77. }
  78. c.JSON(http.StatusOK, gin.H{
  79. "msg": "login success",
  80. })
  81. })
  82. r.POST("/signUp", func(c *gin.Context) {
  83. var signUp SignUp
  84. if err := c.ShouldBind(&signUp); err != nil {
  85. errs, ok := err.(validator.ValidationErrors)
  86. if !ok {
  87. c.JSON(http.StatusOK, gin.H{
  88. "msg": err.Error(),
  89. })
  90. return
  91. }
  92. c.JSON(http.StatusBadRequest, gin.H{
  93. "error": RemoveTopStruct(errs.Translate(trans)),
  94. })
  95. return
  96. }
  97. c.JSON(http.StatusOK, gin.H{
  98. "msg": "signUp success",
  99. })
  100. })
  101. r.Run(":8777")
  102. }
测试
  1. import requests
  2. #login
  3. resp = requests.post("http://127.0.0.1:8777/loginJSON", json={
  4. "user": "xdd",
  5. "password": "1233"
  6. })
  7. print(resp.text)
  1. import requests
  2. #signUp
  3. resp = requests.post("http://127.0.0.1:8777/signUp", json={
  4. "age": 18,
  5. "name": "xdd",
  6. "email": "12@qq.com",
  7. "password": "aaa",
  8. "re_password": "aaa",
  9. })
  10. print(resp.text)

中间件和next函数

Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。

默认启动

  1. // 默认启动方式,包含 Logger、Recovery 中间件
  2. r := gin.Default()

使用中间件

  1. func main() {
  2. // 创建一个不包含中间件的路由器
  3. r := gin.New()
  4. // 全局中间件
  5. // 使用 Logger 中间件
  6. r.Use(gin.Logger())
  7. // 使用 Recovery 中间件
  8. r.Use(gin.Recovery())
  9. // 路由添加中间件,可以添加任意多个
  10. r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
  11. // 路由组中添加中间件
  12. // authorized := r.Group("/", AuthRequired())
  13. // exactly the same as:
  14. authorized := r.Group("/")
  15. // per group middleware! in this case we use the custom created
  16. // AuthRequired() middleware just in the "authorized" group.
  17. authorized.Use(AuthRequired())
  18. {
  19. authorized.POST("/login", loginEndpoint)
  20. authorized.POST("/submit", submitEndpoint)
  21. authorized.POST("/read", readEndpoint)
  22. // nested group
  23. testing := authorized.Group("testing")
  24. testing.GET("/analytics", analyticsEndpoint)
  25. }
  26. // Listen and serve on 0.0.0.0:8080
  27. r.Run(":8080")
  28. }

自定义组件

  1. func main() {
  2. r := gin.New()
  3. r.Use(Logger())
  4. r.GET("/test", func(c *gin.Context) {
  5. example := c.MustGet("example").(string)
  6. log.Println(example)
  7. })
  8. r.Run(":8777")
  9. }
  10. func Logger() gin.HandlerFunc {
  11. return func(c *gin.Context) {
  12. t := time.Now()
  13. c.Set("example", "123")
  14. c.Next()
  15. end := time.Since(t)
  16. log.Println(end)
  17. status := c.Writer.Status()
  18. log.Println(status)
  19. }
  20. }

通过c.abort()终止中间件后续逻辑的执行