GO语言 gin框架 简述

原文地址 基本路由 · Go语言中文文档

一、简介

    Gin是一个golang的轻量级web框架,性能不错,API友好。

    Gin支持Restful风格的API,可以直接从URL路径上接收api参数或者URL参数,也可是使用json或者表单 数据绑定的方式接收参数。

    Gin响应前端的方式,可以使用的方式包括 json、结构体、protobuff的、XML、YAML。

    Gin可以使用路由分组的方式管理API,支持api路径重定向

    Gin的路由库用的是 httprouter,路由节点的数据结构是压缩字典树,提高路由效率。

    Gin支持全局中间件和局部中间件,支持中间件分段逻辑的Next方法

    Gin支持cookie和Session的方法去识别和验证客户端。

    Gin支持 Air 实时监听代码文件自动重新编译执行。

二、gin路由

1. 基本路由

    gin 框架中采用的路由库是基于 httprouter 做的,是第三方HTTP路由包,特点高性能、可扩展

(1) 使用方式:

     New()函数生成了一个 Router对象 。

     GET()方法 或 POST()方法 注册一个适配路径的响应函数  

     将 Router对象 作为参数传给 ListenAndServe()函数 启动HTTP服务。

router := httprouter.New()
router.GET("/", handleFunc)
http.ListenAndServe(":8080", router)

(2) httprouter 为常用的HTTP方法提供快捷使用方式:

     获取:  func (r *Router) GET(path string, handle Handle)

     添加:  func (r *Router) POST(path string, handle Handle)

     修改:  func (r *Router) PUT(path string, handle Handle)

     删除:  func (r *Router) DELETE(path string, handle Handle)

(3) httprouter 包中对URL使用两种匹配模式:

     形如/user/name的精确匹配

     形如/user/*name的匹配所有的模式

(4) 可以处理二级域名。先 根据域名获取对应的Handler路由,然后调用分发机制去处理。

func main() {
    ......
	//分别处理不同的二级域名
	hs := make(HostMap)
	hs["sub1.localhost:8080"] = userRouter
	hs["sub2.localhost:8080"] = dataRouter
    //一级域名:localhost,二级域名:sub1.localhost
	http.ListenAndServe(":8080", hs)
}

type HostMap map[string]http.Handler

func (hs HostMap) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//先根据域名获取对应的Handler路由,然后调用处理
	if handler := hs[r.Host]; handler != nil {
		handler.ServeHTTP(w, r)
	}
}
2. Restful风格的API

    gin支持Restful风格的API,即: URL定位资源,用HTTP描述操作。例如:

(1) 获取文章 /blog/getXxx Get blog/Xxx

(2) 添加 /blog/addXxx POST blog/Xxx

(3) 修改 /blog/updateXxx PUT blog/Xxx

(4) 删除 /blog/delXxxx DELETE blog/Xxx

3. API参数

    Api参数就是在Api地址上输入的参数。

    可以通过Context的Param方法来获取API参数

func main() {
    r := gin.Default()
    r.GET("/user/:name/*action", func(c *gin.Context) {
        name := c.Param("name")
        action := c.Param("action")
        action = strings.Trim(action, "/") //截取/后面的内容
        c.String(http.StatusOK, name+" is "+action)
    })
    r.Run(":8000") //监听8080端口
}

 在浏览器输入:   http://localhost:8080/user/枯藤/doview,获得name参数"枯藤",action参数 "doview"

4. URL参数

   URL参数就是在用Get方式,在?后面输入的参数。

   可以通过DefaultQuery()或Query()方法获取URL参数

r.GET("/user", func(c *gin.Context) {
    name := c.DefaultQuery("name", "枯藤")    //name是参数名称,枯藤是默认值
    c.String(http.StatusOK, fmt.Sprintf("hello %s", name))
})

 在浏览器输入:   http://localhost:8080/user?name=乌鸦,获得name参数"乌鸦"

5. 表单参数

(1) 表单传输为 post请求。http常见的传输格式:

    application/json

    application/x-www-form-urlencoded (默认)

    multipart/form-data

(2) 表单参数可以通过 PostForm() 方法获取

r.POST("/form", func(c *gin.Context) {
    username := c.PostForm("username")
    password := c.PostForm("userpassword")
    c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s", username, password))
})
6. 上传单个文件

(1) multipart/form-data格式用于文件上传

(2) 通过 FormFile() 方法获得文件对象 

r.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")
        c.String(http.StatusOK, file.Filename)
    })
7. 上传多个文件

(1) 上传多个文件也是用 multipart/form-data格式

(2) 通过 MultipartForm() 方法获得文件对象列表

r.POST("/upload", func(c *gin.Context) {
    form, err := c.MultipartForm()
    files := form.File["files"]    // 获取所有图片
    for _, file := range files {    // 遍历所有图片
        c.SaveUploadedFile(file, file.Filename)
    }
})
8. routes group

  routes group(路由分组) 可以分组管理相同的URL。 

   如下代码,v1和v2分别是两个路由组。

func main() {
   r := gin.Default() //创建默认路由
   v1 := r.Group("/v1")    //路由组1
   {   // {} 是书写规范
      v1.GET("/login", login)
      v1.GET("submit", submit)
   }
   v2 := r.Group("/v2")    //路由组2
   {
      v2.POST("/login", login)
      v2.POST("/submit", submit)
   }
   r.Run(":8000")
}
9. 路由原理

  httprouter使用的数据结构是压缩字典树。

  普通的字典树:每个字母都建立一个路由节点

  压缩字典树:只对每个有效前缀建立路由节点。如下图所示:

三、gin数据解析和绑定

     支持三种方式的数据解析,json、表单 和 url参数

1. Json 数据解析和绑定

     使用 context 的 ShouldBindJSON 方法

type Login struct {
   User    string `json:"user"  binding:"required"`
   Pssword string `json:"password"  binding:"required"`
}

func main() {
   r := gin.Default()
   r.POST("loginJSON", func(c *gin.Context) {
      // 声明接收的变量
      var json Login
      // 将request的body中的数据,自动按照json格式解析到结构体
      if err := c.ShouldBindJSON(&json); err != nil {
         ......
      }
      ......
   })
   ......
}
2. 表单数据解析和绑定

   使用 context 的 Bind 方法

type Login struct {
    User    string `form:"username" binding:"required"`
    Pssword string `form:"password" binding:"required"`
}

func main() {
    r := gin.Default()
    r.POST("/loginForm", func(c *gin.Context) {
        var form Login
        // Bind()默认解析并绑定form格式
        // 根据请求头中content-type自动推断
        if err := c.Bind(&form); err != nil {
            ......
        }
        ......
    })
    ......
}
3. URI数据解析和绑定

   使用 context 的 ShouldBindUri 方法

type Login struct {
    User    string `uri:"user" xml:"user" binding:"required"`
    Pssword string `uri:"password" xml:"password" binding:"required"`
}

func main() {
    r := gin.Default()
    r.GET("/:user/:password", func(c *gin.Context) {
        if err := c.ShouldBindUri(&login); err != nil {
            .......
        }
        .......
    })
    .......
}

四、gin 渲染

1. 各种数据格式的响应

(1) json 响应

c.JSON(200, gin.H{"message": "someJSON", "status": 200})

(2) 结构体 响应

var msg struct {
    Name    string
    Message string
}
msg.Name = "root"
msg.Message = "message"
c.JSON(200, msg)

(3) XML,YAML 响应

c.XML(200, gin.H{"message": "abc"})
c.YAML(200, gin.H{"name": "zhangsan"})

(4) protobuf 响应

data := &protoexample.Test{
    Label: &label,
    Reps:  reps,
}
c.ProtoBuf(200, data)
2. HTML模板渲染

   gin支持加载 HTML模板, 然后根据模板参数进行配置并返回相应的数据。

   本质上就是字符串替换。

func main() {
    r := gin.Default()
    r.LoadHTMLGlob("tem/*")    //加载模板文件
    r.GET("/index", func(c *gin.Context) {
        //index.html就是具体的模板文件
        c.HTML(http.StatusOK, "index.html", gin.H{"title": "我是测试", "ce": "123456"})
    })
    r.Run()
}
3. 重定向

  可以使用 context 的  Redirect 方法进行重定向

func main() {
    r := gin.Default()
    r.GET("/redirect_me", func(c *gin.Context) {
        c.Redirect(http.StatusMovedPermanently, "http://www.5lmh.com")
    })
    r.Run()
}

  当客户端请求 /redirect_me 时,服务器将重定向到 https://www.5lmh.com

4. 同步异步

  goroutine机制可以实现异步处理,但不应该使用原始上下文,必须使用它的只读副本。

func main() {
    r := gin.Default()
    r.GET("/long_async", func(c *gin.Context) { 
        copyContext := c.Copy()    // 需要拷贝一个副本
        go func() {    // 异步处理
            time.Sleep(3 * time.Second)
            log.Println("异步执行:" + copyContext.Request.URL.Path)
        }()
    })
    r.Run(":8000")
}

五、gin中间件

1. 全局中间件

    所有请求都经过此中间件。

    实现代码如下:

func MiddleWare() gin.HandlerFunc {
    ......
}

func main() {
    r := gin.Default()
    r.Use(MiddleWare())
    r.Run()
}
2. Next()方法

    当程序执行到context.Next时,会转而先去执行具体的业务逻辑。

    执行完业务逻辑处理函数之后,程序会再次回到context.Next处,继续执行中间件后续的代码。

func MiddleWare() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("中间件开始执行了")
        c.Next()    //转去执行业务逻辑
        //业务逻辑执行完,返回此处,继续执行中间件代码
        .......
        fmt.Println("中间件执行完毕", status)
    }
}

func main() {
    r := gin.Default()
    r.Use(MiddleWare())    // 注册中间件
    r.GET("/ce", func(c *gin.Context) {
        ......
    })
    r.Run()
}

  解释原文 Golang gin 中间件、context.Next函数_gin context.next-CSDN博客

3. 局部中间件

    中间件只在具体某个路由生效,不使用 r.use() 定义的中间件。

func main() {
    r := gin.Default()
    //只在 /ce 的路由里使用局部中间件 PartMiddleWare()
    r.GET("/ce", PartMiddleWare(), func(c *gin.Context) { 
        ......
    })
    r.Run()
}

  解释原文 局部生效的中间件_如何使用局部中间件-CSDN博客

六、会话控制

 1. Cookie介绍

(1) HTTP是无状态协议,服务器不能记录浏览器的访问状态,不能区分两次请求是否由同一个客户端发出。

(2) Cookie 就是一段可以区分不同客户端的信息,由服务器创建,发送给浏览器,浏览器保存。

(3) 浏览器向服务器发送请求时,都会同时将Cookie发送给服务器,服务器根据处理请求。

2. Cookie的使用

   登录时设置cookie,其他请求检验cookie,代码如下:

func AuthMiddleWare() gin.HandlerFunc {
   return func(c *gin.Context) {
      //2.获取cookie并校验
      if cookie, err := c.Cookie("abc"); err == nil {
         if cookie == "123" {
            c.Next() //3.cookie检验通过,执行请求逻辑
            return
         }
      }
      ......
      return
   }
}

func main() {
   r := gin.Default()
   r.GET("/login", func(c *gin.Context) {
      c.SetCookie("abc", "123", 60, "/", "localhost", false, true) //1.登录成功,设置cookie
      c.String(200, "Login success!")
   })
   ......
}
3. Cookie的缺点

(1) 不安全,明文,容易泄露信息

(2) 可以被浏览器禁用。

(3) 有数量限制。某些浏览器对某个域名的cookie有数量限制,大概50个。

4. Sessions

(1) session和cookie 实现的目标是一致的,但实现的方法不同;

(2) session 是另一种记录客户状态的机制, 不同的是 Cookie 保存在客户端浏览器中,而 session保存在服务器

(3) 浏览器第一次访问服务器时,服务器端会创建一个 session 对象,生成一个类似于 key,value 的键值对, 然后将 value 保存到服务器,将 key(cookie)返回到浏览器(客户)端。
      浏览器下次访问时会携带 key(cookie),找到对应的 session(value)。

(4) sessions包地址: github.com/gorilla/sessions

七、参数验证

1. 结构体验证

   用gin框架的数据验证,可以不用解析数据,减少if else,会简洁许多。

   比如,在定义结构体时,添加如下 binding:"required,gt=10",表示不能为空并且大于10

type Person struct {
    //不能为空并且大于10
    Age      int       `form:"age" binding:"required,gt=10"`
}
 2. 自定义验证

    可以自定义验证函数,并注册到 validator中。

    包地址:gopkg.in/go-playground/validator.v9/translations

type Person struct {
    //1.在binding上使用自定义的 参数名称 stringCheckName
    Name    string `form:"name" binding:"stringCheckName"`
}
//2.自定义的校验方法
func checkStringValid(v *validator.Validate, ......) bool {
    if value, ok := field.Interface().(string); ok {
        return value != "" && !("5lmh" == value) //字段不能为空,并且不等于5lmh
    }
    return true
}
func main() {
    r := gin.Default()
    // 3、将我们自定义的校验方法 和 参数名称 注册到 validator中
    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
        v.RegisterValidation("stringCheckName", checkStringValid)
    }
}
3. 多语言翻译验证

   如需要自定义返回信息的语言,比如部分用户返回中文,部分返回英文。

   可以使用  validator.v9/translations

import (
    ut "github.com/go-playground/universal-translator"
    en_translations "gopkg.in/go-playground/validator.v9/translations/en"
)
func startPage(c *gin.Context) {
    locale := c.DefaultQuery("locale", "zh")  //1.获得前端使用语言
    //2.获得翻译器
    en := en.New()
    zh := zh.New()
    Uni = ut.New(en, zh)
    trans, _ := Uni.GetTranslator(locale)     
    //3.注册翻译器
    Validate = validator.New()
    en_translations.RegisterDefaultTranslations(Validate, trans) 
    //4.解析结构体,获得翻译过的内容
    user := User{}
    c.ShouldBind(&user)
    err := Validate.Struct(user)
}

八、其他

1. 日志

  使用 io.MultiWriter  和 gin.DefaultWriter

import (
    "io"
    "os"
)
func main() {
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f) //将日志写入文件
    //gin.DefaultWriter = io.MultiWriter(f, os.Stdout) //将日志同时写入文件和控制台
}
2. Air 实时加载

    在开发调试的时候,变更代码之后需要按下Ctrl+C停止程序并重新编译再执行,不是很方便。

    Air能够实时监听项目的代码文件,在代码发生变更之后自动重新编译并执行,提高开发效率。

3. gin验证码

   为了防止接口被恶意频繁调用,可以采用加验证码的方式。

   库地址:github.com/dchest/captcha

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/657137.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue.js中如何实现以列表首列为表头

前言 一般情况table列表的展示&#xff0c;列头都在第一横行&#xff0c;此方法用于列头在第一列的情况。 效果图 核心代码 <template><div><table class"data-table"><tr v-for"(column, columnIndex) in columns" :key"col…

心链4---搜索页面前后端业务实现以及分布式session的共享实现

心链 — 伙伴匹配系统 搜索详情页面 之前前端的代码写到了搜索页面可以挑选搜索标签&#xff0c;并没有去根据具体标签搜索用户。这里就开始实现。 新建SearchResultPage.vue&#xff0c;并添加相关路由。 在搜索页添加搜索按钮&#xff0c;和触发点击。搜索页选择标签&#x…

华为云Astro Zero低代码平台案例:小、轻、快、准助力销售作战数字化经营

客户背景&#xff1a; 随着业务的不断扩展&#xff0c;华为云某一线作战团队发现&#xff0c;原本基于线上Excel的项目跟踪方式面临新的挑战&#xff1a;多区域、多场景下的业务管理越来越复杂&#xff0c;项目管道存在多种不可控因素&#xff0c;客户关系、进展跟踪同步不及时…

三步走,Halo DB 安装指引

前文介绍了国产数据库新星 Halo 数据库是什么&#xff0c; 哈喽&#xff0c;国产数据库&#xff01;Halo DB! ★ HaloDB是基于原生PG打造的新一代高性能安全自主可控全场景通用型统一数据库。 业内首次创造性的提出插件式内核架构设计&#xff0c;通过配置的方式&#xff0c;适…

部署八戒-Chat-1.8B 模型

1 简单介绍 八戒-Chat-1.8B 八戒-Chat-1.8B是运用 InternLM2-Chat-1.8B 模型进行微调训练的优秀成果。其中&#xff0c;八戒-Chat-1.8B 是利用《西游记》剧本中所有关于猪八戒的台词和语句以及 LLM API 生成的相关数据结果&#xff0c;进行全量微调得到的猪八戒聊天模型。作为 …

LeetCode---链表

203. 移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 代码示例1&#xff1a;(直接使用原来的链表来进行移除节点操作) //时间复杂度: O(n) //空间复杂度: O(1) class Solu…

FANUC机器人点位IO监控指令TC_ONLINE

一、系统变量中打开该指令 在示教器系统变量页面中找到其中的MIX_LOGIC变量&#xff0c;点击enter进入变量设置页面 找到其中的USE_TCOL变量将其中的值改为true 即可在IO显示页面中找到TC_ONLINE的监控选项 在显示页面中也可找到其中的监控条件 二、在点位指令中添加点逻辑指令…

内网安全--隧道技术-MSF上线本地

免责声明:本文仅做技术交流与学习... 不得不说,小白最近也是用上了viper,这里要特别感谢一下my bro 北岭敲键盘的荒漠猫 MSF--viper: --生成马子-->上线 --进入meterpreter. 1-查看路由,添加路由. 查看路由信息 : run autoroute -p run post/multi/manage/autoroute 添加…

电脑卡顿---WINDOWS任何关闭应用开机自启动

打开windows11的控制面板&#xff0c;点击应用&#xff0c;点击启动 如下图圈出来的地方就是开机自启动的开关按键。

Elasticsearch8.13.4版本的Docker启动关闭HTTPS

博主环境是&#xff1a; 开发环境&#xff1a;SpringbootElasticSearch客户端对应的starter 2.6.3版本 maven配置 <!-- ElasticSearch --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elas…

嵌入式UI开发-lvgl+wsl2+vscode系列:4、动画(Animations)

文章目录 一、前言二、动画示例1、示例1&#xff08;基础按钮label的组合动画&#xff09;2、示例2&#xff08;回放效果动画&#xff09;3、示例3&#xff08;贝塞尔曲线3动画&#xff09;4、示例4&#xff08;动画时间轴&#xff09; 三、最后 一、前言 接下来我们进行动画的…

Go 使用 RabbitMQ---------------之一

RabbitMQ 是一种消息代理。消息代理的主要目的是接收、存储并转发消息。在复杂的系统设计和微服务架构中,RabbitMQ 经常被用作中间件来处理和转发系统之间的消息,以确保数据的一致性和可靠性。正是因为提供了可靠的消息机制、跟踪机制和灵活的消息路由,常常被用于排队算法、…

【做一道算一道】力扣332.重新安排行程

332.重新安排行程 给定一个机票的字符串二维数组 [from, to]&#xff0c;子数组中的两个成员分别表示飞机出发和降落的机场地点&#xff0c;对该行程进行重新规划排序。所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必…

区间相交-435. 无重叠区间,56. 合并区间

题目连接及描述 435. 无重叠区间 - 力扣&#xff08;LeetCode&#xff09; 56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 题目分析 二维数组&#xff0c;数组中每个元素为大小为2的一维数组&#xff0c;求移除区间的最小数量&#xff0c;使剩余区间互不重叠。今天写…

Golang原生http实现中间件

Golang原生http实现中间件 中间件&#xff08;middleware&#xff09;&#xff1a;常被用来做认证校验、审计等 大家常用的Iris、Gin等web框架&#xff0c;都包含了中间件逻辑。但有时我们引入该框架显得较为繁重&#xff0c;本文将介绍通过golang原生http来实现中间件操作。全…

小熊家务帮day5 客户管理模块1 (小程序认证,手机验证码认证等)

客户管理模块 1.认证模块1.1 认证方式介绍1.1.1 小程序认证1.1.2 手机验证码登录1.1.3 账号密码认证 1.2 小程序认证1.2.1 小程序申请1.2.2 创建客户后端工程jzo2o-customer1.2.3 开发部署前端1.2.4 小程序认证流程1.2.4.1 customer小程序认证接口设计Controller层Service层调用…

使用Spring Boot编写的小项目

加法计算器 前端代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> <…

杭州威雅学校:在学业与生活平衡中找到更好的自己

进入威雅杭州校园&#xff0c; 沿湖边小道步行约5分钟&#xff0c; 四栋寄宿学院与教学区隔湖相望&#xff0c; 威雅人更喜欢叫他们&#xff1a; 「Cavell」&「Dove」 「Elgar」&「Hawking」 提起「寄宿制」&#xff0c;人们本能地会把它和「住校」划等号。 这种…

【官方指南】3ds Max中纹理贴图问题及正确解决方案

在使用3ds Max进行设计和制作时&#xff0c;纹理贴图是一个非常重要的环节。然而&#xff0c;许多用户在使用过程中常会遇到各种纹理贴图问题。为此&#xff0c;Autodesk官方提供了一些有效的解决方案&#xff0c;可以解决90%的纹理贴图难题。这里小编都帮大家整理好了&#xf…

【加密与解密(第四版)】第十二章笔记

第十二章 注入技术 12.1 DLL注入方法 在通常情况下&#xff0c;程序加载 DLL的时机主要有以下3个&#xff1a;一是在进程创建阶段加载输入表中的DLL&#xff0c;即俗称的“静态输人”;二是通过调用 LoadLibrary(Ex)主动加载&#xff0c;称为“动态加载”&#xff1b;三是由于系…