Gin框架介绍

介绍

Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。

快速入门

安装gin

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

引入gin

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

开始

package main

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

func main() {
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
router.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

路由

  • 普通路由

    router.GET("/", func)
    router.POST("/login", func)
    router.Any("/login", func)
  • 路由分组

    // 简单的路由组: v1
    {
    v1 := router.Group("/v1")
    v1.POST("/login", loginEndpoint)
    v1.POST("/submit", submitEndpoint)
    v1.POST("/read", readEndpoint)
    } // 简单的路由组: v2
    {
    v2 := router.Group("/v2")
    v2.POST("/login", loginEndpoint)
    v2.POST("/submit", submitEndpoint)
    v2.POST("/read", readEndpoint)
    }
  • RESTFUL

    router.GET("/user", QueryFunc)	//查询
    router.Post("/user", AddFunc) // 新增
    router.Delete("/user", DeleteFunc) // 删除
    router.PUT("/user", UpdateFunc) // 更新(客户端提供完整数据)
    router.PATCH("/user", PatchUpdateFunc) // 更新(客户端提供需要修改的数据)
  • 重定向

    // 重定向到外部
    router.GET("/test", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
    }) // 重定向到内部
    router.POST("/test", func(c *gin.Context) {
    c.Redirect(http.StatusFound, "/foo")
    }) router.GET("/test", func(c *gin.Context) {
    c.Request.URL.Path = "/test2"
    router.HandleContext(c)
    })
    router.GET("/test2", func(c *gin.Context) {
    c.JSON(200, gin.H{"hello": "world"})
    })
  • 静态文件

    func main() {
    router := gin.Default()
    router.Static("/assets", "./assets") // 文件目录
    router.StaticFS("/more_static", http.Dir("my_file_system"))
    router.StaticFile("/favicon.ico", "./resources/favicon.ico") // 单独的文件 // 监听并在 0.0.0.0:8080 上启动服务
    router.Run(":8080")
    }

输出

  • XML/JSON/TOML/YAML/ProtoBuf

    c.JSON(http.StatusOK, struct/gin.H)
    c.XML(http.StatusOK, struct/gin.H)
    c.YAML(http.StatusOK, struct/gin.H)
    c.ProtoBuf(http.StatusOK, struct/gin.H)
    ...
    可以到定义文件中去看更多的输出方法
  • HTML

    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>
    func main() {
    router := gin.Default()
    router.LoadHTMLGlob("templates/**/*")
    router.GET("/posts/index", func(c *gin.Context) {
    c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
    "title": "Posts",
    })
    })
    router.GET("/users/index", func(c *gin.Context) {
    c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
    "title": "Users",
    })
    })
    router.Run(":8080")
    } templates/posts/index.tmpl
    {{ define "posts/index.tmpl" }}
    <html><h1>
    {{ .title }}
    </h1>
    <p>Using posts/index.tmpl</p>
    </html>
    {{ end }} templates/users/index.tmpl
    {{ define "users/index.tmpl" }}
    <html><h1>
    {{ .title }}
    </h1>
    <p>Using users/index.tmpl</p>
    </html>
    {{ end }}
    自定义模板渲染器
    ...

参数

  • 参数绑定

    ShouldBind: 自动识别参数,并绑定对应字段到结构体中
    
    ShouldBindJSON	tag:json
    ShouldBindXML tag:xml
    ShouldBindQuery tag:form
    ShouldBindYAML tag:yaml
    ShouldBindTOML tag:toml
    ShouldBindHeader tag:header 无法自动识别
    ShouldBindUri tag:uri 无法自动识别 type formA struct {
    Foo string `json:"foo" xml:"foo" binding:"required" form:"foo"`
    }
    type formA struct {
    Foo string `json:"foo" xml:"foo" binding:"required"`
    } type formB struct {
    Bar string `json:"bar" xml:"bar" binding:"required"`
    } func SomeHandler(c *gin.Context) {
    objA := formA{}
    objB := formB{}
    // c.ShouldBind 使用了 c.Request.Body,不可重用。
    if errA := c.ShouldBind(&objA); errA == nil {
    c.String(http.StatusOK, `the body should be formA`)
    // 因为现在 c.Request.Body 是 EOF,所以这里会报错。
    } else if errB := c.ShouldBind(&objB); errB == nil {
    c.String(http.StatusOK, `the body should be formB`)
    } else {
    ...
    }
    }

    要想多次绑定,可以使用 c.ShouldBindBodyWith


    func SomeHandler(c *gin.Context) {
    objA := formA{}
    objB := formB{}
    // 读取 c.Request.Body 并将结果存入上下文。
    if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
    c.String(http.StatusOK, `the body should be formA`)
    // 这时, 复用存储在上下文中的 body。
    } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
    c.String(http.StatusOK, `the body should be formB JSON`)
    // 可以接受其他格式
    } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
    c.String(http.StatusOK, `the body should be formB XML`)
    } else {
    ...
    }
    }
    c.MustBindWith(&obj, binding.JSON)
    如果发生绑定错误,则请求终止,并设置错误码为400。ShouldBind()返回错误给开发者,不会导致请求终止。
  • 非绑定获取

    r.GET("/:u/:p", func)
    c.Param("u") // url: /11/22 r.GET("/", func)
    c.Query("u") // url: /?u=11
    c.DefaultQuery("u", "222") r.GET("/", func)
    c.PostForm("u") // 获取表单中字段的值
    c.DefaultPostForm("u", "222")

中间件

  • 调用栈

    func mw1() gin.HandlerFunc {
    return func(c *gin.Context) {
    fmt.Println("mw1 before")
    c.Next()
    fmt.Println("mw1 after")
    }
    } func mw2() gin.HandlerFunc {
    return func(c *gin.Context) {
    fmt.Println("mw2 before")
    c.Next()
    fmt.Println("mw2 after")
    }
    } func Middleware() {
    r := gin.Default() r.GET("/", mw1(), mw2(), func(c *gin.Context) {
    fmt.Println("self")
    c.String(http.StatusOK, "self")
    }) err := r.Run(":8080")
    if err != nil {
    panic(err)
    }
    } 输出:
    mw1 before
    mw2 before
    self
    mw2 after
    mw1 after
  • 用户认证

    // 模拟一些私人数据
    var secrets = gin.H{
    "foo": gin.H{"email": "foo@bar.com", "phone": "123433"},
    "austin": gin.H{"email": "austin@example.com", "phone": "666"},
    "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"},
    } func main() {
    router := gin.Default() // 路由组使用 gin.BasicAuth() 中间件
    // gin.Accounts 是 map[string]string 的一种快捷方式
    authorized := router.Group("/admin", gin.BasicAuth(gin.Accounts{
    "foo": "bar",
    "austin": "1234",
    "lena": "hello2",
    "manu": "4321",
    })) // /admin/secrets 端点
    // 触发 "localhost:8080/admin/secrets
    authorized.GET("/secrets", func(c *gin.Context) {
    // 获取用户,它是由 BasicAuth 中间件设置的
    user := c.MustGet(gin.AuthUserKey).(string)
    if secret, ok := secrets[user]; ok {
    c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
    } else {
    c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
    }
    }) // 监听并在 0.0.0.0:8080 上启动服务
    router.Run(":8080")
    }使用中间件
  • 使用中间件

    func main() {
    // 新建一个没有任何默认中间件的路由
    r := gin.New() // 全局中间件
    // Logger 中间件将日志写入 gin.DefaultWriter,即使你将 GIN_MODE 设置为 release。
    // By default gin.DefaultWriter = os.Stdout
    router.Use(gin.Logger()) // Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500。
    router.Use(gin.Recovery()) // 你可以为每个路由添加任意数量的中间件。
    router.GET("/benchmark", MyBenchLogger(), benchEndpoint) // 认证路由组
    // authorized := router.Group("/", AuthRequired())
    // 和使用以下两行代码的效果完全一样:
    authorized := router.Group("/")
    // 路由组中间件! 在此例中,我们在 "authorized" 路由组中使用自定义创建的
    // AuthRequired() 中间件
    authorized.Use(AuthRequired())
    {
    authorized.POST("/login", loginEndpoint)
    authorized.POST("/submit", submitEndpoint)
    authorized.POST("/read", readEndpoint) // 嵌套路由组
    testing := authorized.Group("testing")
    testing.GET("/analytics", analyticsEndpoint)
    } // 监听并在 0.0.0.0:8080 上启动服务
    router.Run(":8080")
    }

模型验证

  • 官方验证器

    Gin使用 go-playground/validator/v10 进行验证。 查看标签用法的全部文档.

    type LoginInfo struct {
    Username string `json:"username" form:"username" binding:"required"`
    Password string `json:"password" form:"password" binding:"number"`
    Email string `json:"email" form:"email" binding:"email"`
    } func Validator() {
    r := gin.Default() r.GET("/", func(c *gin.Context) {
    login := LoginInfo{}
    err := c.ShouldBind(&login)
    if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
    } c.JSON(http.StatusOK, login)
    }) err := r.Run(":8080")
    if err != nil {
    panic(err)
    }
    }
  • 自定义验证器

    import (
    "net/http"
    "reflect"
    "time" "github.com/gin-gonic/gin"
    "github.com/gin-gonic/gin/binding"
    "github.com/go-playground/validator/v10"
    ) // Booking 包含绑定和验证的数据。
    type Booking struct {
    CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
    CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn,bookabledate" time_format:"2006-01-02"`
    } var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
    date, ok := fl.Field().Interface().(time.Time)
    if ok {
    today := time.Now()
    if today.After(date) {
    return false
    }
    }
    return true
    } func main() {
    route := gin.Default() if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    v.RegisterValidation("bookabledate", bookableDate)
    } route.GET("/bookable", getBookable)
    route.Run(":8085")
    } func getBookable(c *gin.Context) {
    var b Booking
    if err := c.ShouldBindWith(&b, binding.Query); err == nil {
    c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
    } else {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
    }

HTTPS

  • 自有证书

    Openssl 生成证书,如果只是提供API服务,可以用没有经过认证的证书,如果是网站,则需要认证证书

    router.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
  • 开源免费认证证书(Let's Encrypt)

    package main
    
    import (
    "log" "github.com/gin-gonic/autotls"
    "github.com/gin-gonic/gin"
    "golang.org/x/crypto/acme/autocert"
    ) func main() {
    router := gin.Default() // Ping handler
    router.GET("/ping", func(c *gin.Context) {
    c.String(200, "pong")
    }) m := autocert.Manager{
    Prompt: autocert.AcceptTOS,
    HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
    Cache: autocert.DirCache("/var/www/.cache"),
    } log.Fatal(autotls.RunWithManager(r, &m))
    }

Gin框架介绍的更多相关文章

  1. Gin框架介绍及使用

    Gin是一个用Go语言编写的web框架.它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍. 如果你是性能和高效的追求者, 你会爱上Gin. ...

  2. Gin框架介绍与使用

    Gin // 初识 Gin框架 //下载(可能会下载不全.缺什么get什么即可) //go get -u -v github.com/gin-gonic/gin package main import ...

  3. Go语言基础之20--web编程框架之Gin框架

    一.Gin框架介绍 1.1 简介 A. 基于httprouter开发的web框架. http://github.com/julienschmidt/httprouter B. 提供Martini风格的 ...

  4. GO语言GIN框架入门

    Gin框架介绍 Gin是一个用Go语言编写的web框架.它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍. 中文文档 Gin框架安装与使用 ...

  5. 基于gin框架和jwt-go中间件实现小程序用户登陆和token验证

    本文核心内容是利用jwt-go中间件来开发golang webapi用户登陆模块的token下发和验证,小程序登陆功能只是一个切入点,这套逻辑同样适用于其他客户端的登陆处理. 小程序登陆逻辑 小程序的 ...

  6. Gin 框架 - 安装和路由配置

    目录 概述 Gin 安装 路由配置 推荐阅读 概述 看下 Gin 框架的官方介绍: Gin 是一个用 Go (Golang) 编写的 web 框架. 它是一个类似于 martini 但拥有更好性能的 ...

  7. Go最火的Gin框架简单入门

    Gin 介绍 Gin 是一个 Golang 写的 web 框架,具有高性能的优点,,基于 httprouter,它提供了类似martini但更好性能(路由性能约快40倍)的API服务.官方地址:htt ...

  8. 基于gin框架搭建的一个简单的web服务

    刚把go编程基础知识学习完了,学习的时间很短,可能还有的没有完全吸收.不过还是在项目中发现知识,然后在去回顾已学的知识,现在利用gin这个web框架做一个简单的CRUD操作. 1.Go Web框架的技 ...

  9. gin框架实现一个简单的项目 ③

    承接:gin框架封装自己的路由 ② 对于一个项目来说,需要将各个功能模块分开,也就是所谓的三层模型,这里介绍一下个人的做法: contorller主要负责路由 model主要负责程序输入输出的数据 s ...

  10. gin框架教程三:JWT的使用

    JWT介绍 JWT (JSON Web Token) 是一种规范.这个规范允许我们使用JWT在用户和服务器之间安全传递信息. JWT的组成: jwt分3个部分,Header 头部.Payload 载荷 ...

随机推荐

  1. uni-app小程序登录后…

    前情 最近新接了一个全新项目,是类似商城的小程序项目,我负责从0开始搭建小程序,我选用的技术栈是uni-app技术栈,其中就有一个用户登录功能,小程序部分页面是需要登录才可以查看的,对于未登录的用户需 ...

  2. WPF的Image控件图片不能显示出来

    在Visual studio中,将图片的属性的"生成操作"从"无"改为"资源". 最终解决问题:

  3. systemctl服务文件管理指南

    systemctl命令概述 systemctl是 Linux 系统中用于管理系统服务的命令,是systemd初始化系统的一部分.它可以用于启动.停止.重启和重新加载服务,查看服务状态以及设置默认启动级 ...

  4. 「Note」POI 套题

    POI 2011 \(\color{limegreen}{P3524}\) 此题是奇妙题. 每次删两个不连通的点,最多删掉 \(\frac{n}{3}\) 个点, 剩下的点一定都在团内,选 \(\fr ...

  5. dev-cpp简单使用教程

    最近在准备蓝桥的比赛,而蓝桥要用dev-cpp,但自己第一次接触,不太会用.防止大家出现和我一样的问题,所以简单分享一下如何使用 1.打开软件界面,弹窗只是一些使用技巧,直接关闭就好 2.文件-新建文 ...

  6. [python]requests VS httpx VS aiohttp

    前言 前段时间想着把一个python服务的接口逐渐改成异步的,其中用到requests的地方就要改成httpx或者aiohttp,有点好奇异步请求相较于同步请求有哪些提升,遂做了点小实验. 首先有个服 ...

  7. snmp总结一:概述

    snmp总结一:概述 SNMP概述 SNMP是英文"Simple Network Management Protocol"的缩写,中文意思是"简单网络管理协议" ...

  8. 浅谈pytest+HttpRunner如何展开接口测试

    数栈是云原生-站式数据中台PaaS,我们在github和gitee上有一个有趣的开源项目:FlinkX,FlinkX是一个基于Flink的批流统一的数据同步工具,既可以采集静态的数据,也可以采集实时变 ...

  9. CBV添加装饰器

    CBV添加装饰器 from django.utils.decorators import method_decorator (1)添加在函数上 class CbvTest(View): @method ...

  10. SpringBoot扩展点全攻略:让你的代码像积木一样灵活组装

    SpringBoot扩展点全攻略:让你的代码像积木一样灵活组装 小李正在开发一个电商系统,老板突然说:"我们要在用户登录时发送短信通知,在订单支付后要积分奖励,在系统启动时要预热缓存...& ...