框架一贯是便捷开发被的利器,能让开发者很快的左侧连做出用,甚至有些时候,脱离了框架,一些开发者都未会师刻画程序了。成长终归不晤面轻易,从写有程序拿到成就感,再届精晓框架,快捷构造采纳,当那一个点都贯虱穿杨的时刻,可以品尝改造部分框架,或是自己创制一个。

一度自己以为Python世界里之框架都足足多矣,后来察觉相相比golang简直小巫见大巫。golang提供的net/http库已经特别好了,对于http的情商的贯彻大好,基于那个再造框架,也不汇合是难事,因而生态中起了成千上万框架。既然构造框架的门槛变低了,那么小门槛同样为会师带来质量参差不齐的框架。

观测了几乎单框架,通过该github的活跃度,维护的team,以及生环境被的使用率。发现Gin要么一个好学习之翩翩框架。

Gin

Gin是一个golang的微框架,封装相比优雅,API友好,源码注释相比较显然,已经揭橥了1.0版本。具有高速灵,容错方便等特征。其实对于golang而言,web框架的凭而多较Python,Java之类的使稍微。自身的net/http充分简单,性能也酷不易。框架还如是有的常用函数或者工具的联谊。借助框架开发,不仅可以节省很多常用的包带来的工夫,也助长集体的编码风格及变异规范。

上面就Gin的用法做一个简约的介绍。

先是需要设置,安装相比简单,使用go get即可

图片 1图片 2

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

View Code

gin的版托管再
gopkg的网站上。我于安装之过程被,gokpg卡住了,后来只好按照gin里的godep的公文,把响应的源码从github上下载,然后copy到相应之目。

至于golang的保管管理与依靠,我们随后再也研究。

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也设想了,并且给有了一个优雅的方案:

图片 3图片 4

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

View Code

用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=@

表单上传

面大家运用的且是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的法力类似:

图片 5图片 6

☁  ~  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

View Code

`使用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。

图片 7图片 8

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

    })

View Code

结果如下:

图片 9图片 10

☁  ~  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>%

View Code

重定向

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

图片 11图片 12

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

View Code

分组路由

熟知Flask的同学应该非常理解蓝图分组。Flask提供了蓝图用于管理团队分组api。gin也供了这样的效益,让你的代码逻辑更是模块化,同时分组也易于定义中间件的下限制。

图片 13图片 14

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

View Code

访问功能如下:

图片 15图片 16

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

View Code

middleware中间件

golang的net/http设计之一律大特色就是专门容易构建中件。gin也供了近乎之中等件。需要注意的凡中件就对注册了之路由函数起效用。对于分组路由,嵌套使用当中件,能够界定中间件的企图范围。中间件分为全局中件,单个路由于中间件和群组中间件。

大局中件

事先定义一个中路件函数:

图片 17图片 18

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

View Code

该函数很简短,只谋面被c上下文添加一个性能,并赋值。后面的路由处理器,可以依照被中件装饰后领到其价值。需要专注,尽管号称也全局中件,只要报中间件的进程在此以前设置的路由,将非会面让注册的中级件所影响。只有注册了中间件转代码的里程由于函数规则,才会于中间件装饰。

图片 19图片 20

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

View Code

运router装饰中件,然后在/middlerware即可读取request的值,注目的在于router.Use(MiddleWare())代码以上的路程由于函数,将未会师发出深受中件装饰的效果。使用花括号包含被点缀的路途由于函数只是一个代码规范,即使没为含有在内的程由于函数,只要使用router举办路由,都等于为点缀了。想使分别权限限制,可以使用组重返的对象注册中件。

图片 21图片 22

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

View Code

假如无注册就运MustGet方读取c的价将晤面抛错,可以以Get方法取而代之。

下面的挂号装饰格局,会被有上边所写的代码都默认使用了router的报过的高中级件。

单个路由于中件

当,gin也提供了针对指定的行程由于函数举行注册。

图片 23图片 24

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

View Code

将上述代码写于
router.Use(Middleware())此前,同样为会晤/before被装饰了中等件。

群组中间件

群组的中间件为仿佛,只要在对于的群组路由上注册中件函数即可:

图片 25图片 26

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

View Code

群组可以嵌套,因为中件为足以因群组的嵌套规则嵌套。

高中级件实践

中等件最特别之意向,莫过于用于一些记录log,错误handler,还有尽管是对有的接口的鉴权。下边就落实一个简易的鉴权中间件。

图片 27图片 28

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

View Code

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

AuthMiddleWare的代码如下:

图片 29图片 30

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

View Code

起上下文的伸手被读取cookie,然后校对cookie,假若来问题,则止请求,直接回,这里用了c.Abort()方法。

图片 31图片 32

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'}

View Code

异步协程

golang的高并发一不行利器就是协程。gin里好依靠协程实现异步任务。因为关乎异步过程,请求的上下文需要copy到异步的上下文,并且那个上下文是惟有念之。

图片 33图片 34

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

View Code

 

每当伏乞的时候,sleep5分钟,同步的逻辑可以视,服务的经过睡眠了。异步的逻辑则相响应重回了,然后程序还当后台的协程处理。

自定义router

gin不仅可动用框架本身的router举行Run,也得以配合以net/http本身的力量:

图片 35图片 36

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

View Code

本来还有一个雅的又开和得了进程的方案。后边将相会追究使用supervisor管理golang的过程。

总结

Gin是一个翩翩而强大的golang
web框架。涉及大开发之功用,大家都做了简要的介绍。关于劳动之起步,请求参数的处理以及响应格式的渲染,以及针对性上传和高中级件鉴权做了例子。更好的左右来自实践,同时gin的源码注释很详细,可以翻阅源码了然再多详细的功能以及魔法特性。

作者:人世间
链接:http://www.jianshu.com/p/a31e4ee25305
來源:简书
作品权归作者所有。商业转载请联系作者得到授权,非商业转载请申明出处。

 





 





















 

 

相关文章

网站地图xml地图