精华内容
下载资源
问答
  • gin介绍
    千次阅读
    2021-11-25 10:54:20

    当前流行的Go语言web框架

    以下是截止到2021.10.03,GitHub上开源的Go Web框架情况。目前Gin是遥遥领先。

    Project NameStarsForksOpen IssuesDescriptionLast Commit
    gin518945889443Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.2021-09-30 02:04:28
    beego27032531627beego is an open-source, high-performance web framework for the Go programming language.2021-09-18 15:08:26
    kit21360219247A standard library for microservices.2021-09-28 15:01:29
    echo20797184165High performance, minimalist Go web framework2021-09-26 15:56:43
    fasthttp16135133646Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http2021-10-01 11:38:31
    fiber1559078937⚡️ Express inspired web framework written in Go2021-10-02 01:54:34
    mux15202141324A powerful HTTP router and URL matcher for building Go web servers with 🦍2021-09-14 12:12:19
    kratos14913300135A Go framework for microservices.2021-09-30 06:31:25
    httprouter13204127563A high performance HTTP request router that scales well2020-09-21 13:50:23
    revel124001402103A high productivity, full-stack web framework for the Go language.2020-07-12 05:57:36
    go-zero11533137234go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.2021-10-02 10:16:59

    Web框架需要做什么

    我们先思考下,一个完整的Web开发框架需要做哪些事情

    组件功能是否必须
    server作为server,监听端口,接受请求
    router路由和分组路由,可以把请求路由到对应的处理函数
    middleware支持中间件,对外部发过来的http请求经过中间件处理,再给到对应的处理函数。例如http请求的日志记录、请求鉴权(比如校验token)、CORS支持、CSRF校验等。
    template engine模板引擎,支持后端代码对html模板里的内容做渲染(render),返回给前端渲染好的html
    ORM对象关系映射,可以把代码里的对象和关系数据库的表、字段做映射关联,通过操作对象来实现数据库的增删查改等操作。

    Gin有什么

    Gin的主要作者是ManuJavierBo-Yi Wu,2016年发布第一个版本,目前是最受欢迎的开源Go框架。

    Gin除了支持上面表格里列的server、router、middleware和template之外,还支持

    • Crash-free:崩溃恢复,Gin可以捕捉运行期处理http请求过程中的panic并且做recover操作,让服务一直可用。

    • JSON validation:JSON验证。Gin可以解析和验证request里的JSON内容,比如字段必填等。当然开发人员也可以选择使用第三方的JSON validation工具,比如beego validation

    • Error management:错误管理。Gin提供了一种简单的方式可以收集http request处理过程中的错误,最终中间件可以选择把这些错误写入到log文件、数据库或者发送到其它系统。

    • Middleware Extendtable:可以自定义中间件。Gin除了自带的官方中间件之外,还支持用户自定义中间件,甚至可以把自己开发的中间件提交到官方代码仓库里。

    Gin本身不支持ORM,如果想在Gin框架里使用ORM,可以选择使用第三方的ORM,比如gorm

    文章开源地址:

    https://github.com/jincheng9/go-tutorial

    会有一个系列分享Go Web开发的方方面面。

    欢迎大家关注公众号:coding进阶,学习更多Go知识。

    References

    更多相关内容
  • gin介绍

    2019-09-09 14:41:28
    Gin介绍与应用 Gin是一个golang的web框架,Gin像是一些常用函数或者工具的集合。具有快速灵活,容错方便等特点。Gin自身的net/http足够简单,性能也非常不错。 Gin的官网:https://github.com/gin-gonic/gin 安装...

    Gin的介绍与应用

    Gin是一个golang的web框架,Gin像是一些常用函数或者工具的集合。具有快速灵活,容错方便等特点。Gin自身的net/http足够简单,性能也非常不错。
    Gin的官网:https://github.com/gin-gonic/gin
    安装前保证git和go都安装好
    windows安装Gin,在cmd中输入: go get github.com/gin-gonic/gin.在这里插入图片描述
    .
    Linux下安装Gin:go get -u github.com/gin-gonic/gin,如果因为缺少组件而失败,就下载缺乏的组件再安装。

    1,第一个gin实例:Hello world

    在这里插入图片描述
    运行结果:
    在这里插入图片描述
    使用时:import "github.com/gin-gonic/gin".
    使用gin的Default方法创建一个路由handler。然后通过HTTP方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。c.String用来返回字符串,最后是启动路由的Run方法监听端口。

    router := gin.Default() //创建路由

    router.GET //用于获取资源

    gin.SetMode()//设置gin模式

    router.POST("/somePost", posting)//用于创建子资源

    router.PUT("/somePut", putting)//用于创建、更新资源

    router.DELETE("/someDelete", deleting)//用于删除资源

    2,第二个实例:快速匹配参数

    在这里插入图片描述
    运行结果:
    在这里插入图片描述

    3,第三个实例:获取普通get参数结果

    在这里插入图片描述
    运行结果:
    在这里插入图片描述

    展开全文
  • Go语言Web框架--Gin介绍和使用

    万次阅读 多人点赞 2018-07-23 11:05:11
    下面就Gin的用法做一个简单的介绍。 首先需要安装,安装比较简单,使用go get -u(更新) 即可: go get gopkg.in/gin-gonic/gin.v1 gin的版本托管再 gopkg的网站上。我在安装的过程中,gokpg卡住了,后来...

    所谓框架

    框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了。成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应手的时候,可以尝试改造一些框架,或是自己创造一个。

    曾经我以为Python世界里的框架已经够多了,后来发现相比golang简直小巫见大巫。golang提供的net/http库已经很好了,对于http的协议的实现非常好,基于此再造框架,也不会是难事,因此生态中出现了很多框架。既然构造框架的门槛变低了,那么低门槛同样也会带来质量参差不齐的框架。

    考察了几个框架,通过其github的活跃度,维护的team,以及生产环境中的使用率。发现Gin还是一个可以学习的轻巧框架。


    Gin

    Gin是一个golang的微框架封装比较优雅API友好,源码注释比较明确,已经发布了1.0版本。具有快速灵活容错方便等特点。其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

    下面就Gin的用法做一个简单的介绍。

    首先需要安装,安装比较简单,使用go get -u(更新) 即可:

    go get gopkg.in/gin-gonic/gin.v1

    gin的版本托管再 gopkg的网站上。我在安装的过程中,gokpg卡住了,后来不得不根据gin里的godep的文件,把响应的源码从github上下载,然后copy到对应的目录。


    Hello World

    使用Gin实现Hello world非常简单,创建一个router,然后使用其Run的方法:

    import ( 
        "gopkg.in/gin-gonic/gin.v1" 
        "net/http" 
    ) 
    func main(){ 
        router := gin.Default() 
        router.GET("/", func(c *gin.Context) { 
        c.String(http.StatusOK, "Hello World") 
        }) 
    router.Run(":8000") 
    }
    

    简单几行代码,就能实现一个web服务。使用gin的Default方法创建一个路由handler。然后通过HTTP方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。最后是启动路由的Run方法监听端口。麻雀虽小,五脏俱全。当然,除了GET方法,gin也支持POST,PUT,DELETE,OPTION等常用的restful方法。


    restful路由

    gin的路由来自httprouter库。因此httprouter具有的功能,gin也具有,不过gin不支持路由正则表达式:

    func main(){ 
        router := gin.Default() 
        router.GET("/user/:name", func(c *gin.Context) { 
            name := c.Param("name") 
            c.String(http.StatusOK, "Hello %s", name) 
        }) 
    }
    
    

    冒号:加上一个参数名组成路由参数。可以使用c.Params的方法读取其值。当然这个值是字串string。诸如/user/rsj217,和/user/hello都可以匹配,而/user//user/rsj217/不会被匹配。

    ☁ ~ curl http://127.0.0.1:8000/user/rsj217 
    Hello rsj217%                  
    
    ☁ ~ curl http://127.0.0.1:8000/user/rsj217/ 
    404 page not found%            
    
    ☁ ~ curl http://127.0.0.1:8000/user/ 
    404 page not found%
    
    
    

    除了:,gin还提供了*号处理参数,*号能匹配的规则就更多。

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

    访问效果如下

    ☁  ~  curl http://127.0.0.1:8000/user/rsj217/
    rsj217 is /%                       
    
    ☁  ~  curl http://127.0.0.1:8000/user/rsj217/中国
    rsj217 is /中国%

    query string参数与body参数

    web提供的服务通常是client和server的交互。其中客户端向服务器发送请求,除了路由参数,其他的参数无非两种,查询字符串query string和报文体body参数。所谓query string,即路由用,用?以后连接的key1=value2&key2=value2的形式的参数。当然这个key-value是经过urlencode编码。

    query string

    对于参数的处理,经常会出现参数不存在的情况,对于是否提供默认值,gin也考虑了,并且给出了一个优雅的方案:

    func main(){ 
        router := gin.Default() 
    
        router.GET("/welcome", func(c *gin.Context) { 
            firstname := c.DefaultQuery("firstname", "Guest") 
            lastname := c.Query("lastname") 
            c.String(http.StatusOK, "Hello %s %s", firstname, lastname) 
            }) 
    
        router.Run() 
    }
    
    

    使用c.DefaultQuery方法读取参数,其中当参数不存在的时候,提供一个默认值。使用Query方法读取正常参数,当参数不存在的时候,返回空字串:

    ☁ ~ curl http://127.0.0.1:8000/welcome 
    Hello Guest % 
    
    ☁ ~ curl http://127.0.0.1:8000/welcome\?firstname\=中国 
    Hello 中国 % 
    
    ☁ ~ curl http://127.0.0.1:8000/welcome\?firstname\=中国\&lastname\=天朝 
    Hello 中国 天朝% 
    
    ☁ ~ curl http://127.0.0.1:8000/welcome\?firstname\=\&lastname\=天朝 
    Hello 天朝% 
    
    ☁ ~ curl http://127.0.0.1:8000/welcome\?firstname\=%E4%B8%AD%E5%9B%BD 
    Hello 中国 %
    
    

    之所以使用中文,是为了说明urlencode。注意,当firstname为空字串的时候,并不会使用默认的Guest值,空值也是值,DefaultQuery只作用于key不存在的时候,提供默认值。

    body

    http的报文体传输数据就比query string稍微复杂一点,常见的格式就有四种。例如application/jsonapplication/x-www-form-urlencoded, application/xmlmultipart/form-data。后面一个主要用于图片上传。json格式的很好理解,urlencode其实也不难,无非就是把query string的内容,放到了body体里,同样也需要urlencode。默认情况下,c.PostFROM解析的是x-www-form-urlencodedfrom-data的参数。

    func main(){ 
        router := gin.Default() 
        router.POST("/form_post", func(c *gin.Context) { 
            message := c.PostForm("message") 
            nick := c.DefaultPostForm("nick", "anonymous") 
            c.JSON(http.StatusOK, gin.H{ 
                "status": gin.H{ 
                    "status_code": http.StatusOK, 
                    "status": "ok", 
                }, 
                "message": message, 
                "nick": nick,         
            }) 
        }) 
    }

    与get处理query参数一样,post方法也提供了处理默认参数的情况。同理,如果参数不存在,将会得到空字串。

    ☁ ~ curl -X POST http://127.0.0.1:8000/form_post -H "Content-Type:application/x-www-form-urlencoded" -d "message=hello&nick=rsj217" | python -m json.tool % Total % Received % Xferd 
    
    Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    100 104 100 79 100 25 48555 15365 --:--:-- --:--:-- --:--:-- 79000 
    { 
        "message": "hello", 
        "nick": "rsj217", 
        "status": { 
            "status": "ok", 
            "status_code": 200 
        } 
    }

    前面我们使用c.String返回响应,顾名思义则返回string类型。content-type是plain或者text。调用c.JSON则返回json数据。其中gin.H封装了生成json的方式,是一个强大的工具。使用golang可以像动态语言一样写字面量的json,对于嵌套json的实现,嵌套gin.H即可。

    发送数据给服务端,并不是post方法才行,put方法一样也可以。同时querystring和body也不是分开的,两个同时发送也可以:

    func main(){ 
        router := gin.Default() 
        router.PUT("/post", func(c *gin.Context) { 
            id := c.Query("id") 
            page := c.DefaultQuery("page", "0") 
            name := c.PostForm("name") 
            message := c.PostForm("message") 
            fmt.Printf("id: %s; page: %s; name: %s; message: %s \n", id, page, name, message)                   
            c.JSON(http.StatusOK, gin.H{ "status_code": http.StatusOK, }) 
        }) 
    }
    
    

    上面的例子,展示了同时使用查询字串和body参数发送数据给服务器。


    文件上传

    前面介绍了基本的发送数据,其中multipart/form-data转用于文件上传。gin文件上传也很方便,和原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中了。

    func main(){ 
        router := gin.Default() 
        router.POST("/upload", func(c *gin.Context) { 
            name := c.PostForm("name") 
            fmt.Println(name) 
            file, header, err := c.Request.FormFile("upload") if err != nil {     
                c.String(http.StatusBadRequest, "Bad request") 
                return 
            } 
            filename := header.Filename 
            fmt.Println(file, err, filename) 
            out, err := os.Create(filename) 
            if err != nil {
                log.Fatal(err) 
            } 
            defer out.Close() 
            _, err = io.Copy(out, file) 
            if err != nil 
            { 
                log.Fatal(err)
            } 
            c.String(http.StatusCreated, "upload successful") 
        }) 
        router.Run(":8000") 
    }

    使用c.Request.FormFile解析客户端文件name属性。如果不传文件,则会抛错,因此需要处理这个错误。一种方式是直接返回。然后使用os的操作,把文件数据复制到硬盘上。

    使用下面的命令可以测试上传,注意upload为c.Request.FormFile指定的参数,其值必须要是绝对路径:

    curl -X POST http://127.0.0.1:8000/upload -F "upload=@/Users/ghost/Desktop/pic.jpg" -H "Content-Type: multipart/form-data"

    上传多个文件

    单个文件上传很简单,别以为多个文件就会很麻烦。依葫芦画瓢,所谓多个文件,无非就是多一次遍历文件,然后一次copy数据存储即可。下面只写handler,省略main函数的初始化路由和开启服务器监听了:

    router.POST("/multi/upload", func(c *gin.Context) { 
        err := c.Request.ParseMultipartForm(200000) 
        if err != nil { 
            log.Fatal(err) 
        } 
        formdata := c.Request.MultipartForm 
        files := formdata.File["upload"] 
    
        for i, _ := range files { / 
            file, err := files[i].Open() 
            defer file.Close() 
            if err != nil { 
                log.Fatal(err) 
            } 
    
            out, err := os.Create(files[i].Filename) 
            defer out.Close() 
            if err != nil { 
                log.Fatal(err) 
            } 
    
            _, err = io.Copy(out, file) 
            if err != nil { 
                log.Fatal(err) 
            } 
    
            c.String(http.StatusCreated, "upload successful") 
        } 
    })

    与单个文件上传类似,只不过使用了c.Request.MultipartForm得到文件句柄,再获取文件数据,然后遍历读写。

    使用curl上传

    curl -X POST http://127.0.0.1:8000/multi/upload -F "upload=@/Users/ghost/Desktop/pic.jpg" -F "upload=@/Users/ghost/Desktop/journey.png" -H "Content-Type: multipart/form-data"

    表单上传

    上面我们使用的都是curl上传,实际上,用户上传图片更多是通过表单,或者ajax和一些requests的请求完成。下面展示一下web的form表单如何上传。

    我们先要写一个表单页面,因此需要引入gin如何render模板。前面我们见识了c.String和c.JSON。下面就来看看c.HTML方法。

    首先需要定义一个模板的文件夹。然后调用c.HTML渲染模板,可以通过gin.H给模板传值。至此,无论是String,JSON还是HTML,以及后面的XML和YAML,都可以看到Gin封装的接口简明易用。

    创建一个文件夹templates,然后再里面创建html文件upload.html:

    <!DOCTYPE html> 
    <html lang="en"> 
    <head> 
        <meta charset="UTF-8"> 
        <title>upload</title> 
    </head> 
    
    <body> 
    <h3>Single Upload</h3> 
    <form action="/upload", method="post" enctype="multipart/form-data"> 
        <input type="text" value="hello gin" /> 
        <input type="file" name="upload" /> 
        <input type="submit" value="upload" /> 
    </form> 
    
    <h3>Multi Upload</h3> 
    <form action="/multi/upload", method="post" enctype="multipart/form-data"> 
        <input type="text" value="hello gin" /> 
        <input type="file" name="upload" /> 
        <input type="file" name="upload" /> 
        <input type="submit" value="upload" /> 
    </form> 
    
    </body> 
    </html>

    upload 很简单,没有参数。一个用于单个文件上传,一个用于多个文件上传。

      router.LoadHTMLGlob("templates/*")
        router.GET("/upload", func(c *gin.Context) {
            c.HTML(http.StatusOK, "upload.html", gin.H{})
        })
    

    使用LoadHTMLGlob定义模板文件路径。


    参数绑定

    我们已经见识了x-www-form-urlencoded类型的参数处理,现在越来越多的应用习惯使用JSON来通信,也就是无论返回的response还是提交的request,其content-type类型都是application/json的格式。而对于一些旧的web表单页还是x-www-form-urlencoded的形式,这就需要我们的服务器能改hold住这多种content-type的参数了。

    Python的世界里很好解决,毕竟动态语言不需要实现定义数据模型。因此可以写一个装饰器将两个格式的数据封装成一个数据模型。golang中要处理并非易事,好在有gin,他们的model bind功能非常强大。

    type User struct { 
        Username string `form:"username" json:"username" binding:"required"` 
        Passwd string `form:"passwd" json:"passwd" bdinding:"required"` 
        Age int `form:"age" json:"age"` 
    } 
    
    func main(){ 
        router := gin.Default() 
    
        router.POST("/login", func(c *gin.Context) { 
            var user User 
            var err error 
            contentType := c.Request.Header.Get("Content-Type") 
    
            switch contentType { 
                case "application/json": 
                    err = c.BindJSON(&user) 
                case "application/x-www-form-urlencoded": 
                    err = c.BindWith(&user, binding.Form) 
            } 
            if err != nil { 
                fmt.Println(err) 
                log.Fatal(err) 
            } 
    
            c.JSON(http.StatusOK, gin.H{ 
                "user": user.Username, 
                "passwd": user.Passwd, 
                "age": user.Age, 
            }) 
        }) 
    }

    先定义一个User模型结构体,然后针对客户端的content-type,一次使BindJSONBindWith方法。

    ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/x-www-form-urlencoded" -d "username=rsj217&passwd=123&age=21" | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    100 79 100 46 100 33 41181 29543 --:--:-- --:--:-- --:--:-- 46000
    { 
        "age": 21, 
        "passwd": "123", 
        "username": "rsj217" 
    }
    
     ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/x-www-form-urlencoded" -d "username=rsj217&passwd=123&new=21" | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    100 78 100 45 100 33 37751 27684 --:--:-- --:--:-- --:--:-- 45000 
    { 
        "age": 0, 
        "passwd": "123", 
        "username": "rsj217" 
    } 
    
    ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/x-www-form-urlencoded" -d "username=rsj217&new=21" | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0curl: (52) Empty reply from server 
    No JSON object could be decoded

    可以看到,结构体中,设置了binding标签的字段(username和passwd),如果没传会抛错误。非banding的字段(age),对于客户端没有传,User结构会用零值填充。对于User结构没有的参数,会自动被忽略。

    改成json的效果类似:

    ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/json" -d '{"username": "rsj217", "passwd": "123", "age": 21}' | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    100 96 100 46 100 50 32670 35511 --:--:-- --:--:-- --:--:-- 50000 
    { 
        "age": 21, 
        "passwd": "123", 
        "username": "rsj217" 
    } 
    
    ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/json" -d '{"username": "rsj217", "passwd": "123", "new": 21}' | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    100 95 100 45 100 50 49559 55066 --:--:-- --:--:-- --:--:-- 50000 
    { 
        "age": 0, 
        "passwd": "123", 
        "username": "rsj217" 
    } 
    
    ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/json" -d '{"username": "rsj217", "new": 21}' | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0curl: (52) Empty reply from server 
    No JSON object could be decoded 
    
    ☁ ~ curl -X POST http://127.0.0.1:8000/login -H "Content-Type:application/json" -d '{"username": "rsj217", "passwd": 123, "new": 21}' | python -m json.tool % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 
    0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0curl: (52) Empty reply from server 
    No JSON object could be decoded
    

    使用json还需要注意一点,json是有数据类型的,因此对于 {"passwd": "123"}{"passwd": 123}是不同的数据类型,解析需要符合对应的数据类型,否则会出错。

    当然,gin还提供了更加高级方法,c.Bind,它会更加content-type自动推断是bind表单还是json的参数。

    router.POST("/login", func(c *gin.Context) 
    { 
        var user User err := c.Bind(&user) 
        if err != nil { 
            fmt.Println(err) 
            log.Fatal(err) 
        } 
        c.JSON(http.StatusOK, gin.H{ 
            "username": user.Username, 
            "passwd": user.Passwd, 
            "age": user.Age, 
        }) 
    })

    多格式渲染

    既然请求可以使用不同的content-type,响应也如此。通常响应会有html,text,plain,json和xml等。
    gin提供了很优雅的渲染方法。到目前为止,我们已经见识了c.String, c.JSON,c.HTML,下面介绍一下c.XML。

    router.GET("/render", func(c *gin.Context) { 
        contentType := c.DefaultQuery("content_type", "json") 
        if contentType == "json" { 
            c.JSON(http.StatusOK, gin.H{ 
            "user": "rsj217", 
            "passwd": "123", 
            }) 
        } else if contentType == "xml" { 
            c.XML(http.StatusOK, gin.H{ 
                "user": "rsj217", 
                "passwd": "123", 
            }) 
        } 
    })

    结果如下:

    ☁ ~ curl http://127.0.0.1:8000/render\?content_type\=json 
    {"passwd":"123","user":"rsj217"} 
    
    ☁ ~ curl http://127.0.0.1:8000/render\?content_type\=xml 
    <map><user>rsj217</user><passwd>123</passwd></map>%

    重定向

    gin对于重定向的请求,相当简单。调用上下文的Redirect方法:

    router.GET("/redict/google", func(c *gin.Context) {
            c.Redirect(http.StatusMovedPermanently, "https://google.com")
    })

    分组路由

    熟悉Flask的同学应该很了解蓝图分组。Flask提供了蓝图用于管理组织分组api。gin也提供了这样的功能,让你的代码逻辑更加模块化,同时分组也易于定义中间件的使用范围。

    v1 := router.Group("/v1") 
    v1.GET("/login", func(c *gin.Context) { 
        c.String(http.StatusOK, "v1 login") 
    }) 
    
    v2 := router.Group("/v2") 
    v2.GET("/login", func(c *gin.Context) { 
        c.String(http.StatusOK, "v2 login") 
    })

    访问效果如下:

    ☁  ~  curl http://127.0.0.1:8000/v1/login
    v1 login%                                                                                 
    ☁  ~  curl http://127.0.0.1:8000/v2/login
    v2 login%

    middleware中间件

    golang的net/http设计的一大特点就是特别容易构建中间件。gin也提供了类似的中间件。需要注意的是中间件只对注册过的路由函数起作用。对于分组路由,嵌套使用中间件,可以限定中间件的作用范围。中间件分为全局中间件,单个路由中间件和群组中间件。


    全局中间件

    先定义一个中间件函数:

    func MiddleWare() gin.HandlerFunc { 
        return func(c *gin.Context) { 
            fmt.Println("before middleware") 
            c.Set("request", "clinet_request") 
            c.Next() 
            fmt.Println("before middleware") 
        } 
    }

    该函数很简单,只会给c上下文添加一个属性,并赋值。后面的路由处理器,可以根据被中间件装饰后提取其值。需要注意,虽然名为全局中间件,只要注册中间件的过程之前设置的路由,将不会受注册的中间件所影响。只有注册了中间件一下代码的路由函数规则,才会被中间件装饰。

    router.Use(MiddleWare()) { 
        router.GET("/middleware", func(c *gin.Context) { 
            request := c.MustGet("request").(string) 
            req, _ := c.Get("request") 
            c.JSON(http.StatusOK, gin.H{ 
                "middile_request": request, "request": req, 
            }) 
        }) 
    }

    使用router装饰中间件,然后在/middlerware即可读取request的值,注意在router.Use(MiddleWare())代码以上的路由函数,将不会有被中间件装饰的效果。

    使用花括号包含被装饰的路由函数只是一个代码规范,即使没有被包含在内的路由函数,只要使用router进行路由,都等于被装饰了。想要区分权限范围,可以使用组返回的对象注册中间件。

    ☁  ~  curl  http://127.0.0.1:8000/middleware
    {"middile_request":"clinet_request","request":"clinet_request"}

    如果没有注册就使用MustGet方法读取c的值将会抛错,可以使用Get方法取而代之。

    上面的注册装饰方式,会让所有下面所写的代码都默认使用了router的注册过的中间件。


    单个路由中间件

    当然,gin也提供了针对指定的路由函数进行注册。

    router.GET("/before", MiddleWare(), func(c *gin.Context) { 
        request := c.MustGet("request").(string) 
        c.JSON(http.StatusOK, gin.H{ 
            "middile_request": request, 
        }) 
    })

    群组中间件

    群组的中间件也类似,只要在对于的群组路由上注册中间件函数即可:

    authorized := router.Group("/", MyMiddelware()) 
    // 或者这样用: 
    authorized := router.Group("/") 
    authorized.Use(MyMiddelware()) { 
        authorized.POST("/login", loginEndpoint) 
    }

    群组可以嵌套,因为中间件也可以根据群组的嵌套规则嵌套。


    中间件实践

    中间件最大的作用,莫过于用于一些记录log,错误handler,还有就是对部分接口的鉴权。下面就实现一个简易的鉴权中间件。

    router.GET("/auth/signin", func(c *gin.Context) { 
        cookie := &http.Cookie{ 
            Name: "session_id", 
            Value: "123", 
            Path: "/", 
            HttpOnly: true, 
        } 
        http.SetCookie(c.Writer, cookie) 
        c.String(http.StatusOK, "Login successful") 
    }) 
    
    router.GET("/home", AuthMiddleWare(), func(c *gin.Context) { 
        c.JSON(http.StatusOK, gin.H{"data": "home"}) 
    })

    登录函数会设置一个session_id的cookie,注意这里需要指定path为/,不然gin会自动设置cookie的path为/auth,一个特别奇怪的问题。/home的逻辑很简单,使用中间件AuthMiddleWare注册之后,将会先执行AuthMiddleWare的逻辑,然后才到/home的逻辑。

    AuthMiddleWare的代码如下:

    func AuthMiddleWare() gin.HandlerFunc { 
        return func(c *gin.Context) { 
            if cookie, err := c.Request.Cookie("session_id"); err == nil { 
                value := cookie.Value fmt.Println(value) 
                if value == "123" { c.Next() return } 
            } 
            c.JSON(http.StatusUnauthorized, gin.H{ 
                "error": "Unauthorized", 
            })
            c.Abort() 
            return 
        } 
    }

    从上下文的请求中读取cookie,然后校对cookie,如果有问题,则终止请求,直接返回,这里使用了c.Abort()方法。

    In [7]: resp = requests.get('http://127.0.0.1:8000/home') 
    
    In [8]: resp.json() 
    Out[8]: {u'error': u'Unauthorized'} 
    
    In [9]: login = requests.get('http://127.0.0.1:8000/auth/signin') 
    
    In [10]: login.cookies 
    Out[10]: <RequestsCookieJar[Cookie(version=0, name='session_id', value='123', port=None, port_specified=False, domain='127.0.0.1', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)]> 
    
    In [11]: resp = requests.get('http://127.0.0.1:8000/home', cookies=login.cookies) 
    
    In [12]: resp.json() 
    Out[12]: {u'data': u'home'}
    

    异步协程

    golang的高并发一大利器就是协程。gin里可以借助协程实现异步任务。因为涉及异步过程,请求的上下文需要copy到异步的上下文,并且这个上下文是只读的。

    router.GET("/sync", func(c *gin.Context) { 
        time.Sleep(5 * time.Second) 
        log.Println("Done! in path" + c.Request.URL.Path) 
    }) 
    
    router.GET("/async", func(c *gin.Context) { 
        cCp := c.Copy() 
        go func() { 
            time.Sleep(5 * time.Second) 
            log.Println("Done! in path" + cCp.Request.URL.Path) 
        }() 
    })

    在请求的时候,sleep5秒钟,同步的逻辑可以看到,服务的进程睡眠了。异步的逻辑则看到响应返回了,然后程序还在后台的协程处理。


    自定义router

    gin不仅可以使用框架本身的router进行Run,也可以配合使用net/http本身的功能:

    func main() {
        router := gin.Default()
        http.ListenAndServe(":8080", router)
    }

    或者

    func main() { 
        router := gin.Default() 
        s := &http.Server{ 
            Addr: ":8000", 
            Handler: router, 
            ReadTimeout: 10 * time.Second, 
            WriteTimeout: 10 * time.Second, 
            MaxHeaderBytes: 1 << 20, 
        } 
        s.ListenAndServe() 
    }

    当然还有一个优雅的重启和结束进程的方案。后面将会探索使用supervisor管理golang的进程。


    总结

    Gin是一个轻巧而强大的golang web框架。涉及常见开发的功能,我们都做了简单的介绍。关于服务的启动,请求参数的处理和响应格式的渲染,以及针对上传和中间件鉴权做了例子。更好的掌握来自实践,同时gin的源码注释很详细,可以阅读源码了解更多详细的功能和魔法特性。


    End

    展开全文
  • 本文是gin介绍和使用的第一篇文章。一、简要介绍Gin的官方说明如下:Gin is a web framework written in Go (Golang). It features a martini-like API with much betterperformance, up to 40 times faster thanks ...

    本文是gin介绍和使用的第一篇文章。

    一、简要介绍

    Gin的官方说明如下:

    Gin is a web framework written in Go (Golang). It features a martini-like API with much better

    performance, up to 40 times faster thanks to httprouter. If you need performance and good

    productivity, you will love Gin.

    简单来说,Gin是一个Go的微框架,基于 httprouter,提供了类似martini(也是一个go web框架)但更好性能的API服务。

    Gin具有运行速度快、良好的分组路由、合理的异常捕获和错误处理、优良的中间件支持和 json处理支持等优点,是一款非常值得推荐的web框架。

    借助框架开发,我们不仅可以省去很多常用的封装带来的时间,也有助于良好的团队编码风格的和编码规范的养成。

    二、使用详解

    1.安装

    要安装Gin包,首先需要安装Go((Go版本1.10+)并设置Go工作区

    下载并安装:

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

    在代码中导入它

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

    2. 简单示例:

    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

    }

    简单几行代码,就实现了一个web服务。

    首先,使用gin的Default方法创建一个路由handle;

    然后,通过HTTP方法绑定路由规则和路由函数;

    最后,启动路由的Run方法监听端口。

    不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。

    3. 常用请求方法

    除了GET方法,gin也支持POST,PUT,DELETE,OPTION等常用的restful方法:

    func main() {

    // Creates a gin router with default middleware:

    // logger and recovery (crash-free) middleware

    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)

    // By default it serves on :8080 unless a

    // PORT environment variable was defined.

    router.Run()

    // router.Run(":3000") for a hard coded port

    }

    4. 获取路径中的参数

    gin的路由来自httprouter库。因此httprouter具有的功能,gin也具有,不过gin不支持路由正则表达式:

    package main

    import (

    "fmt"

    "net/http"

    "github.com/gin-gonic/gin"

    )

    func main() {

    router := gin.Default()

    // This handler will match /user/john but will not match /user/ or /user

    router.GET("/user/:name", func(c *gin.Context) {

    name := c.Param("name")

    c.String(http.StatusOK, "Hello %s", name)

    })

    // Howerer, 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 := fmt.Sprintf("%s is %s", name, 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.String(http.StatusOK, c.Request.URL.String())

    })

    router.Run(":8000")

    }

    冒号加上一个参数名(如上面的":name")组成路由参数。可以使用c.Params的方法读取其值。当然这个值是字串string;

    *号加上一个参数名(如上面的"action")组成路由参数。读取方式与冒号相同,但是号能匹配的规则更多。

    使用curl(也可以使用如Postman等)访问服务,并得到测试结果如下:

    e55e779d629cf27637390ee218ff298a.png

    5. 获取请求参数

    web提供的服务通常是client和server的交互。

    其中客户端向服务器发送请求,除了路由参数,其他的参数无非两种,即查询字符串query string和报文体body参数。

    query string,即路由用?以后连接的key1=value2&key2=value2的形式的参数。当然这个key-value是经过urlencode编码的。

    5.1. 获取Get请求参数

    客户端发起Get请求即使用query string参数,例如:

    curl http://127.0.0.1:8000/welcome\?firstname\=中国\&lastname\=南京

    之所以使用中文,是为了说明urlencode。

    服务端对于参数的处理,经常会出现参数不存在的情况,对于是否提供默认值,gin也考虑了,并且给出了一个优雅的方案:

    使用c.DefaultQuery方法读取参数,其中当参数不存在的时候,提供一个默认值;

    使用c.Query方法读取正常参数,当参数不存在的时候,返回空字串。

    注意:当上述请求中的firstname为空字串的时候,服务端并不会使用默认的Guest值,空值也是值,DefaultQuery只作用于key不存在的时候,提供默认值。

    package main

    import (

    "net/http"

    "github.com/gin-gonic/gin"

    )

    func main() {

    router := gin.Default()

    // Query string parameters are parsed using the existing underlying request object.

    // The request responds to a url matching: /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(":8000")

    }

    5.2. 获取Post请求参数

    POST请求会向服务器提交数据,如提交表单数据,这就需要用到报文体body参数。 http使用报文体传输数据就比query string稍微复杂一点,常见的格式就有四种:

    application/json(json格式数据)

    application/x-www-form-urlencoded(就是把query string的内容,放到了body体里)

    application/xml (xml格式数据)

    multipart/form-data (图片上传数据)

    默认情况下,c.PostFrom解析的是x-www-form-urlencoded或from-data的参数:

    package main

    import (

    "net/http"

    "github.com/gin-gonic/gin"

    )

    func main() {

    router := gin.Default()

    router.POST("/form_post", func(c *gin.Context) {

    message := c.PostForm("message")

    nick := c.DefaultPostForm("nick", "anonymous")

    c.JSON(http.StatusOK, gin.H{

    "status": "posted",

    "message": message,

    "nick": nick,

    })

    })

    router.Run(":8000")

    }

    与get处理query参数一样,post也提供了处理默认参数的方法c.DefaultPostForm。同理,对于c.PostForm,如果参数不存在,将会得到空字串。

    前面我们使用c.String返回响应,顾名思义则返回string类型数据,content-type是plain或者text。

    这里我们调用c.JSON则返回json类型数据。其中gin.H封装了生成json的方式,是一个强大的工具。使用Go可以像动态语言一样写字面量的json,对于嵌套json的实现,嵌套gin.H即可。

    5.3. Get参数和Post参数混合使用

    发送数据给服务端,并不是post方法才行,put方法一样也可以。同时querystring和body也不是分开的,两个同时发送也可以:

    package main

    import (

    "fmt"

    "net/http"

    "github.com/gin-gonic/gin"

    )

    func main() {

    router := gin.Default()

    router.PUT("/put", func(c *gin.Context) {

    id := c.Query("id")

    page := c.DefaultQuery("page", "0")

    name := c.PostForm("name")

    message := c.PostForm("message")

    fmt.Printf("id: %s; page: %s; name: %s; message: %s\n", id, page, name, message)

    c.JSON(http.StatusOK, gin.H{

    "status": "puted",

    "info": gin.H{

    "id": id,

    "page": page,

    "name": name,

    "message": message,

    },

    })

    })

    router.Run(":8000")

    }

    上面的例子,展示了同时使用查询字串和body参数发送数据给服务器。

    6. 文件上传

    前面介绍了向服务器发送请求的基本方法,其中multipart/form-data专用于文件上传。Gin文件上传也很方便,和原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中了。

    上传文件的文件名可以由用户自定义,所以可能包含非法字符串,为了安全起见,应该由服务端统一文件名规则

    6.1. 单文件上传

    package main

    import (

    "fmt"

    "io"

    "net/http"

    "os"

    "github.com/gin-gonic/gin"

    )

    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

    name := c.DefaultPostForm("name", "template")

    fmt.Println("name:", name)

    file, header, err := c.Request.FormFile("file")

    if err != nil {

    c.String(http.StatusBadRequest, "bad request: %s", err.Error())

    return

    }

    filename := header.Filename

    out, err := os.Create(filename)

    if err != nil {

    c.String(http.StatusNotFound, "file create err: %s", err.Error())

    return

    }

    defer out.Close()

    _, err = io.Copy(out, file)

    if err != nil {

    c.String(http.StatusNotFound, "file copy err: %s", err.Error())

    return

    }

    c.String(http.StatusCreated, "upload successfully")

    })

    router.Run(":8000")

    }

    使用c.Request.FormFile解析客户端文件name属性。如果不传文件,则会抛错,因此需要处理这个错误。一种方式是直接返回。

    然后使用os的操作,把文件数据复制到硬盘上,最后返回给客户端上传成功的提示。

    由于Go使用UTF-8编码格式,windows下上传其它编码格式文件可能会出现中文乱码问题,可通过另存为UTF-8编码格式文件解决。

    6.2. 多文件上传

    单个文件上传很简单,多文件上传与之类似,所谓多个文件,就是多一层遍历操作,每次遍历的操作步骤与单文件上传完全相同。

    package main

    import (

    "io"

    "net/http"

    "os"

    "github.com/gin-gonic/gin"

    )

    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("/multi/upload", func(c *gin.Context) {

    // multipart form

    err := c.Request.ParseMultipartForm(200000)

    if err != nil {

    c.String(http.StatusBadRequest, "request body out of memeory: %s", err.Error())

    return

    }

    form := c.Request.MultipartForm

    files := form.File["file"]

    for i := range files {

    file, err := files[i].Open()

    if err != nil {

    c.String(http.StatusBadRequest, "file open err: %s", err.Error())

    return

    }

    defer file.Close()

    out, err := os.Create(files[i].Filename)

    if err != nil {

    c.String(http.StatusNotFound, "file create err: %s", err.Error())

    return

    }

    defer out.Close()

    _, err = io.Copy(out, file)

    if err != nil {

    c.String(http.StatusNotFound, "file copy err: %s", err.Error())

    return

    }

    }

    c.String(http.StatusCreated, "upload successfully")

    })

    router.Run(":8000")

    }

    与单个文件上传类似,只不过使用了c.Request.MultipartForm得到文件句柄,再获取文件数据,然后遍历读写。

    6.3. 表单上传

    上面我们使用的都是curl或使用集成工具如Postman上传,实际上,用户上传图片更多是通过表单,或者ajax和一些requests的请求完成。下面展示一下web的form表单如何上传。

    我们先要写一个表单页面,因此需要引入gin如何render(生成)模板。前面我们见识了c.String和c.JSON。下面就来看看c.HTML方法。

    首先需要定义一个模板的文件夹。然后调用c.HTML渲染模板,可以通过gin.H给模板传值。至此,无论是String,JSON还是HTML,以及后面的XML和YAML,都可以看到Gin封装的接口简明易用。

    示例如下:

    创建一个文件夹templates,然后再里面创建html文件upload.html:

    upload

    Single Upload

    Multi Upload

    upload表单很简单,没有参数,两个form表单一个用于单个文件上传,一个用于多个文件上传。

    在原有代码基础上添加如下代码:

    router.LoadHTMLGlob("templates/*")

    router.GET("/upload", func(c *gin.Context) {

    c.HTML(http.StatusOK, "upload.html", gin.H{})

    })

    使用router.LoadHTMLGlob方法定义模板文件路径。

    完整的代码如下:

    package main

    import (

    "fmt"

    "io"

    "net/http"

    "os"

    "github.com/gin-gonic/gin"

    )

    func main() {

    router := gin.Default()

    router.POST("/upload", upload)

    // Set a lower memory limit for multipart forms (default is 32 MiB)

    // router.MaxMultipartMemory = 8 << 20 // 8 MiB

    router.POST("/multi/upload", multiUpload)

    // 此处使用相对路径,实际路径根据模板所在路径作相应调整

    router.LoadHTMLGlob("../templates/*")

    router.GET("/upload", func(c *gin.Context) {

    c.HTML(http.StatusOK, "upload.html", gin.H{})

    })

    router.Run(":8000")

    }

    func upload(c *gin.Context) {

    // single file

    name := c.DefaultPostForm("name", "template")

    fmt.Println("name:", name)

    file, header, err := c.Request.FormFile("file")

    if err != nil {

    c.String(http.StatusBadRequest, "bad request: %s", err.Error())

    return

    }

    filename := header.Filename

    out, err := os.Create(filename)

    if err != nil {

    c.String(http.StatusNotFound, "file create err: %s", err.Error())

    return

    }

    defer out.Close()

    _, err = io.Copy(out, file)

    if err != nil {

    c.String(http.StatusNotFound, "file copy err: %s", err.Error())

    return

    }

    c.String(http.StatusCreated, "upload successfully")

    }

    func multiUpload(c *gin.Context) {

    // multipart form

    err := c.Request.ParseMultipartForm(200000)

    if err != nil {

    c.String(http.StatusBadRequest, "request body out of memeory: %s", err.Error())

    return

    }

    form := c.Request.MultipartForm

    files := form.File["file"]

    for i := range files {

    file, err := files[i].Open()

    if err != nil {

    c.String(http.StatusBadRequest, "file open err: %s", err.Error())

    return

    }

    defer file.Close()

    out, err := os.Create(files[i].Filename)

    if err != nil {

    c.String(http.StatusNotFound, "file create err: %s", err.Error())

    return

    }

    defer out.Close()

    _, err = io.Copy(out, file)

    if err != nil {

    c.String(http.StatusNotFound, "file copy err: %s", err.Error())

    return

    }

    }

    c.String(http.StatusCreated, "upload successfully")

    }

    通过浏览器访问

    http://localhost:8000/upload

    然后选择文件上传即可。

    展开全文
  • gin之基本介绍

    千次阅读 2020-12-09 18:13:39
    一、常见的几种GO语言Web框架 1、Beego面向Go编程语言的开源高性能web框架 https://github.com/astaxie/beego https://beego.me 2、Buffalo使用Go语言快速构建Web应用 ...3、Echo高性能、极简Go语言Web框架 ...
  • 1.下载gin框架 go get -u github.com/gin-gonic/gin 当无法下载时,大概率是被墙了 需要配置环境变量 go env -w GOPROXY=https://goproxy.io,direct go env -w GOPRIVATE=*.corp.example.com 不建议使用 GO111...
  • 大家好,我是煎鱼,从今天开始将会把 Go Gin 的入门系列给更新过来,如果大家有什么问题、建议疑问,欢迎随时交流和碰撞,也可以到 go-gin-example 项目提问。 跟着学,我相信你能够得到你所希望的,共勉。 本文...
  • 从Java转Go,初学Gin框架,最关心的操作就是接收请求与返回响应的问题,本文主要简单介绍一下Gin框架的基本使用。Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点...
  • gin简介和路由(一)

    千次阅读 2020-12-17 10:20:43
    一、Gin 特性 1、快速:路由不使用反射,基于Radix树,内存占用少。 2、中间件:HTTP请求,可先经过一系列中间件处理,例如:Logger,Authorization,GZIP等。这个特性和 NodeJs 的Koa框架很像。中间件机制也极大...
  • Gin 框架介绍(v1.7.1).pdf

    2021-09-28 13:08:33
    关于gin框架的一些原理介绍,适合想了解API框架的同学查看
  • gin-vue-admin

    2021-04-22 10:55:23
    Gin-vue-admin是一个基于vue和gin开发的全栈前后端分离的后台管理系统,集成jwt鉴权,动态路由,动态菜单,casbin鉴权,表单生成器,代码生成器等功能,提供多种示例文件,让您把更多时间专注在业务开发上。...
  • 主要介绍了golang 网络框架之gin的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 本篇文章主要介绍了Go Web框架gin的入门教程,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 目录 前言 正文 Query 参数解析 ...今天,我们就来详细看看 Gin 是如何进行参数解析的。 正文 Query 参数解析 在所有的请求中,Query 参数属于最常见的一种,下面通过一段代码来看一下,代
  • Gin框架介绍及使用

    2022-01-01 20:10:14
    Gin框架介绍及使用 Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍。 如果你是性能和高效的追求者, 你会爱上GinGin框架介绍 Go...
  • 7 Gin框架介绍及使用

    2022-03-25 11:27:10
    Gin框架介绍及使用 Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍。 如果你是性能和高效的追求者, 你会爱上GinGin框架介绍 Go世界里...
  • Golang Gin 框架入门介绍(二)

    千次阅读 2021-11-21 22:38:32
    目录 前言 正文 一、定义 GET, POST, ...上一篇文章介绍Gin 的基本使用方式,今天我们详细看一看 Gin 在接口定义和参数解析方面的内容。 正文 一、定义 GET, POST, PUT, PATCH, DELETE 和 OPTIONS 的接口 p
  • 第一章 gin简介

    2019-09-15 16:23:46
    gin使用go编写的高性能的HTTP Web框架。它具有和Martini类似的API,但是性能却比Martini要高40倍。这是因为gin使用了Httprouter路由框架。 gin的官网:https://gin-gonic.com github:https://github.co...
  • 初识Gin框架1.Gin介绍2.第一个gin网站示例RESTful API 1.Gin介绍 Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架。 它具有类似 Martini 的 API,但性能比 Martini 快 40 倍。如果你需要极好的性能,使用 Gin 吧 ...
  • 我司的 Web 后端服务基本是都是基于 Gin 开发的。 正文 安装 首次使用 Gin 框架时,需要先进行安装,命令如下: go get -u github.com/gin-gonic/gin 可能会出现如下报错信息: # cd .; git clone -- ...
  • GIN框架应用级介绍

    2022-05-04 09:37:18
    官方文档:https://github.com/gin-gonic/gin 安装 go get -u github.com/gin-gonic/gin 使用 import "github.com/gin-gonic/gin" import "net/http" // 使用http包时使用 快速开始 监听8080端口,对于/请求返回...
  • go语言学习(二)——Gin 框架简介

    千次阅读 2020-05-25 21:09:37
    GoWeb开发有很多框架,如Beego、Gin、Revel、Echo、IRis等,学习框架可以快速做开发,对比常见goweb框架,通过其github的活跃度,维护的team,生产环境中的使用率以及师兄的推荐,个人选择了学习Gin这个轻巧框架。...
  • Gin-vue-admin是一个基于vue和gin开发的全栈前后端分离的后台管理系统,集成jwt鉴权,动态路由,动态菜单,casbin鉴权,表单生成器,代码生成器等功能,提供多种示例文件,让您把更多时间专注在业务开发上。...
  • gin框架简介
  • Gin源码库地址: : Gin之所以被很多企业和团队使用,第一个原因是因为速
  • 杜松子酒介绍使用go语言-gin框架实现zip文件的上传,自动解压,查看文件,zip文件的上传,项目的创建和删除主要是管理产品图zip包,自动解压,在线预览软件架构软件架构说明安装教程git clone 去国防部下载使用说明...
  • 基于gin+vue搭建的后台管理系统框架,集成jwt鉴权,权限管理,动态路由,分页封装,多点登录拦截,资源权限,上传下载,代码生成器,表单生成器,通用工作流等基础功能,五分钟一套CURD前后端代码,目前已支持VUE3 ...
  • python的gin库的介绍和使用

    千次阅读 2021-04-18 15:25:56
    python的gin介绍和使用 本文参考官方文档 1.简介 由于现在很多机器学习的实验需要设置繁琐的参数,在多次实验中,有些参数是一样的,为了方便设置参数,Gin库出现了。它允许函数或类被注释为@gin.configurable,这...
  • GinGin框架中间件

    千次阅读 2022-04-15 10:33:31
    Gin中的中间件和我们通常所认识的中间件如缓存中间件(Redis)、消息中间件(Kafaka、MQ)等不一样,Go语言中的中间件更像Spring中的拦截器,根据作用范围又分为全局中间件和局部中间件,下面对中间件这部分进行介绍...
  • gin_日志介绍

    2021-06-20 13:16:45
    可读性 数据分析,二次挖掘 logrus第三方库的使用 一、安装 github.com/sirupsen/logrus 二、使用logrus自定义日志中间件 func LoggerFile(c *gin.Context) { file_dir := "logs/" + "gin_project.log" //写入文件 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,978
精华内容 1,991
关键字:

gin介绍