GO学习笔记(22) - 第三方框架-gin框架

目录

  • 简介
  • 生态框架
  • 安装配置
  • 入门指南

简介

其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

Gin 是一个基于 Go 语言编写的 Web 框架,比近似框架 martini 拥有更好的性能,借助高性能的 httprouter,速度提升了近 40 倍。详细介绍

gin框架应用

  • gorush:Go 编写的通知推送服务器。
  • fnproject:容器原生,云 serverless 平台。
  • photoprism:基于 Go 和 Google TensorFlow 实现的个人照片管理工具。
  • krakend:拥有中间件的超高性能 API 网关。
  • picfit:Go 编写的图像尺寸调整服务器。
  • gotify:基于 WebSocket 进行实时消息收发的简单服务器。
  • cds:企业级持续交付和 DevOps 自动化开源平台。

安装配置

  1. 添加环境变量
GO111MODULE  on
GOPROXY  https://goproxy.cn
GOROOT   是你安装go的路径
  1. 安装
go get -u github.com/gin-gonic/gin
  1. 高性能日志库zap安装
go get -u go.uber.org/zap

基础编程

  • 启动默认引擎(端口8080)
  • middleware应用
  • context的使用
package main

import (
    "github.com/gin-gonic/gin"
    "go.uber.org/zap"
    "math/rand"
    "time"
)

const keyRequestId = "requestId"

func main() {
    //默认服务端引擎
    //http://localhost:8080/ping
    //自动带有日志模块
    r := gin.Default()

    log,err := zap.NewProduction()
    if err != nil{
        panic(err)
    }

    //使用middleware,接入zap日志模块
    r.Use(func(c *gin.Context) {
        //path,response code,log latency,
        start := time.Now()
        c.Next()

        log.Info("incoming request",
            zap.String("path",c.Request.URL.Path),
            zap.Int("status",c.Writer.Status()),
            zap.Duration("elapsed", time.Now().Sub(start)),

        )
    },
    //另外一个use
    //入口,增加requestId
    func(c *gin.Context) {
        c.Set(keyRequestId,rand.Int())
        c.Next()
    })
    r.GET("/ping", func(c *gin.Context) {
        h := gin.H{"message":"pong",}
        if rid,exist := c.Get(keyRequestId); exist{
            h[keyRequestId]=rid
        }
        c.JSON(200,h)
    })

    r.GET("/hello", func(c *gin.Context) {
        c.String(200,"hello")
    })
        //默认8080端口
    r.Run()
}

restful路由

gin的路由来自httprouter库。除“不支持路由正则表达式"之外,httprouter具有的功能,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/不会被匹配。

下例中name代表":"的变量

func main(){
    router := gin.Default()
    
    router.GET("/user/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.String(http.StatusOK, "Hello %s", name)
    })
}
  • 星号:*
    除了:,gin还提供了号处理参数,号能匹配的规则就更多。

下例中action代表"*" 的变量

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/carmen/
carmen is /%          
--                                                         
$  curl http://127.0.0.1:8000/user/carmen/中国
carmen is /中国%

文件上传

  • 上传单个文件
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")
}
  • 上传多个文件
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")

        }

    })

表单上传与gin的render模板

  • 表单如下:
<!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>
  • 后端代码
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,
        })

    })

}

middleware中间件

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

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
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 一、gin简介 Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。 它是一个类似于 mar...
    Every_dawn阅读 2,627评论 1 4
  • 所谓框架 框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写...
    人世间阅读 217,089评论 11 242
  • Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了htt...
    雪上霜阅读 1,739评论 0 1
  • 本来自己打算继续学下beanFactory源码的,但是放假了自己也没什么精神,看源码又要求注意力很集中,所以想着看...
    me_2f11阅读 1,365评论 1 1
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 129,626评论 2 7

友情链接更多精彩内容