美文网首页
Go web 开发框架 - Gin 简述

Go web 开发框架 - Gin 简述

作者: 张云飞Vir | 来源:发表于2020-04-13 12:36 被阅读0次

    0. 背景

    Go 语言开发框架很多,本文介绍Gin。

    Go web 开发框架 - Gin 简述

    Gin 的英文意思是 杜松子酒,在它的官方介绍中提到了它的API 风格是 和 martini 相像的( martini-like )。而 martini 也是一个web框架,有意思的是 martini 的英文是 “马提尼”,也是一种鸡尾酒。

    1. 简介

    Go 是最快的全功能web框架之一,清澈,简洁。它的性能更好,速度快了40倍(相比于 martini 框架)。 Gin 是面向高性能和良好的生产力的选择。

    总结就是:

    • 简洁,晶莹剔透
    • 性能好

    特点:

    • 快: 内存占用小。没有反射。
    • 支持中间件: 通过中间件扩展能力。例如:Logger、授权、GZIP。
    • 故障和恢复:Gin可以捕获HTTP请求期间发生的panic并恢复它。
    • JSON验证: Gin可以解析和验证请求的JSON
    • 路由分组:通过分组方便管理,比如控制授权与不需要授权,不同的API版本等。
    • 错误管理:方便的收集HTTP请求期间发生的所有错误,可以通过中间件可以将它们写入日志文件、数据库并通过网络发送。
    • 内置的视图呈现: 支持MVC,为JSON、XML和HTML呈现提供API。
    • 可扩展:创建新中间件非常简单。

    2. 开始之前

    2.1 安装

    go get -u github.com/gin-gonic/gin
    

    2.2 导入包

    import "github.com/gin-gonic/gin"
    

    2.3 一个快速示例

    简单步骤:

    • 构建一个服务对象,通过 gin.Default()
    • 启动服务,通过 r.Run()

    示例如下:

    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 (for windows "localhost:8080")
    }
    

    2.4 构建时注意事项

    Gin使用encoding/json作为默认的json包,但是您可以通过从其他标记构建来更改为jsoniter。

    $ go build -tags=jsoniter .
    

    3. 使用示例

    3.1 GET, POST,PUT 示例

    形式如 router.GET("/someGet", getting),第一个参数是 url 相对路径,第二个参数是 你的 hadler 处理器。

    hadler 处理器的函数签名是:func(c *gin.Context) { }

    func main() {
        router := gin.Default()
    
        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)
    
        router.Run()
    }
    

    3.2 处理URL路径中的参数(比如:/user/:name)

    Parameters in path
    func main() {
        router := gin.Default()
    
        // 匹配 /user/john
        router.GET("/user/:name", func(c *gin.Context) {
            name := c.Param("name")
            c.String(http.StatusOK, "Hello %s", name)
        })
    
        // However, this one will match /user/john/ and also /user/john/send
        // If no other routers match /user/john, it will redirect to /user/john/
        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)
        })
    
        // For each matched request Context will hold the route definition
        router.POST("/user/:name/*action", func(c *gin.Context) {
            c.FullPath() == "/user/:name/*action" // true
        })
    
        router.Run(":8080")
    }
    

    3.3 读取URL中的查询字符串

    使用: c.DefaultQuery(), 或者 c.Query() 方法。

    func main() {
        router := gin.Default()
    
        // welcome?firstname=Jane&lastname=Doe
        router.GET("/welcome", func(c *gin.Context) {
            firstname := c.DefaultQuery("firstname", "Guest")
            lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
    
            c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
        })
        router.Run(":8080")
    }
    

    3.4 读取URL中的查询字符串

    使用: c.PostForm() 方法

    func main() {
        router := gin.Default()
    
        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,
            })
        })
        router.Run(":8080")
    }
    

    3.5 处理文件上传

    获得文件:
    file, _ := c.FormFile("file")
    保存文件:
    c.SaveUploadedFile(file, dst)

    func main() {
        router := gin.Default()
        // Set a lower memory limit for multipart forms (default is 32 MiB)
        // router.MaxMultipartMemory = 8 << 20  // 8 MiB
        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, dst)
    
            c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
        })
        router.Run(":8080")
    }
    

    3.6 路由分组

    使用 router.Group("/v1") 实现 路由分组。

    Grouping routes
    func main() {
        router := gin.Default()
    
        // Simple group: v1
        v1 := router.Group("/v1")
        {
            v1.POST("/login", loginEndpoint)
            v1.POST("/submit", submitEndpoint)
            v1.POST("/read", readEndpoint)
        }
    
        // Simple group: v2
        v2 := router.Group("/v2")
        {
            v2.POST("/login", loginEndpoint)
            v2.POST("/submit", submitEndpoint)
            v2.POST("/read", readEndpoint)
        }
    
        router.Run(":8080")
    }
    

    3.7 呈现 HTML 视图 ( HTML rendering )

    通过 LoadHTMLGlob() 或者 LoadHTMLFiles() 加载模板
    通过 c.HTML(http.StatusOK, "index.tmpl", gin.H{
    "title": "Main website",
    })

    第一个参数是 http 状态码,第二个参数是模板名,第三个参数是传入的参数值。

    func main() {
        router := gin.Default()
        router.LoadHTMLGlob("templates/*")
        //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
        router.GET("/index", func(c *gin.Context) {
            c.HTML(http.StatusOK, "index.tmpl", gin.H{
                "title": "Main website",
            })
        })
        router.Run(":8080")
    }
    
    

    templates/index.tmpl

    <html>
        <h1>
            {{ .title }}
        </h1>
    </html>
    

    3.8 自定义中间件(Custom Middleware)

    中间件是个函数,签名格式: func(c *gin.Context) {}
    通过 c.Next() 表达继续在 链条中传递。

    func Logger() gin.HandlerFunc {
        return func(c *gin.Context) {
            t := time.Now()
    
            // Set example variable
            c.Set("example", "12345")
    
            // before request
    
            c.Next()
    
            // after request
            latency := time.Since(t)
            log.Print(latency)
    
            // access the status we are sending
            status := c.Writer.Status()
            log.Println(status)
        }
    }
    
    func main() {
        r := gin.New()
        r.Use(Logger())
    
        r.GET("/test", func(c *gin.Context) {
            example := c.MustGet("example").(string)
    
            // it would print: "12345"
            log.Println(example)
        })
    
        // Listen and serve on 0.0.0.0:8080
        r.Run(":8080")
    }
    

    更多内容,请参阅 官方Github

    4. 参考

    官网
    https://gin-gonic.com/

    官方github
    https://github.com/gin-gonic/gin

    官方github 的 readme 翻译
    https://www.jianshu.com/p/98965b3ff638/

    多款 Go 语言开发框架 介绍(含对比)
    https://github.com/speedwheel/awesome-go-web-frameworks/blob/master/README.md#popularity

    Martini是一个强大为了编写模块化Web应用而生的GO语言框架.
    https://github.com/go-martini/martini/blob/master/translations/README_zh_cn.md

    相关文章

      网友评论

          本文标题:Go web 开发框架 - Gin 简述

          本文链接:https://www.haomeiwen.com/subject/djcgmhtx.html