当前位置: 首页 > news >正文

【Gin】Gin框架介绍和使用

一、简单使用Gin框架搭建一个服务器

package mainimport ("github.com/gin-gonic/gin"
)func main() {// 创建一个默认的路由引擎r := gin.Default()// GET 请求方法r.GET("/hello", func(c *gin.Context) {// c.JSON 返回的是JSON格式的数据c.JSON(200, gin.H{"message" : "hello world",})}// 启动HTTP服务器,默认在 0.0.0.0:8080 启动r.Run()
}

       这里,我们只需要记住一下几个函数就可以快速启动一个服务器:还有记住就是一个请求对应一个响应。世界是一个巨大的IO。

gin.Default()  // 创建一个默认的路由引擎GET("/路由", func(c *gin.Context) {}c.JSON(状态码, gin.H{})r.Run() // 启动HTTP服务器

二、RESTful API

       REST 与技术无关,代表的是一种软件架构风格,简单地说,REST的含义就是客户端与服务器之间进行交互的时候,使用HTTP协议中的4种请求方法代表不同的动作。

  • GET用来获取资源
  • POST用来新建资源
  • PUT用来更新资源
  • DELETE用来删除资源

       只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互的。

我们可以来看一看下面的代码:

func main() {r := gin.Default()r.GET("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "GET",})})r.POST("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "POST",})})r.PUT("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "PUT",})})r.DELETE("/book", func(c *gin.Context) {c.JSON(200, gin.H{"message": "DELETE",})})
}

三、Gin获取参数

前三个进行获取参数的函数都有三种方法,且函数的格式基本一样:

3.1 获取 querystring 参数

       querystring 指的是 URL中 ? 后面携带的参数:/user/search?username=小王子&address=沙河,获取请求的 querystring 参数的方法如下:

func main() {//Default返回一个默认的路由引擎r := gin.Default()r.GET("/user/search", func(c *gin.Context) {username := c.DefaultQuery("username", "小王子")//username := c.Query("username")address := c.Query("address")//输出json结果给调用方c.JSON(http.StatusOK, gin.H{"message":  "ok","username": username,"address":  address,})})r.Run()
}c.Query()c.DefaultQuery()

       我之前写的一个项目就是需要处理这种URL,不过是在C++上处理,需要将URL获取到,然后进行字符串的切割。

3.2 获取 form 参数

       当前端请求的数据是通过form表单提交的时候,例如向 /user/search 发一个POST请求,获取请求数据的方式如下:

func main() {//Default返回一个默认的路由引擎r := gin.Default()r.POST("/user/search", func(c *gin.Context) {// DefaultPostForm取不到值时会返回指定的默认值//username := c.DefaultPostForm("username", "小王子")username := c.PostForm("username")address := c.PostForm("address")//输出json结果给调用方c.JSON(http.StatusOK, gin.H{"message":  "ok","username": username,"address":  address,})})r.Run(":8080")
}c.PostForm()c.DefaultPostForm()

3.3 获取 JSON 参数

       当前端请求的数据通过JSON提交的时候,例如向 /json 发送一个JSON格式的POST请求,则请求参数的方式如下:

r.POST("/json", func(c *gin.Context) {// 注意:下面为了举例子方便,暂时忽略了错误处理b, _ := c.GetRawData()  // 从c.Request.Body读取请求数据// 定义map或结构体var m map[string]interface{}// 反序列化_ = json.Unmarshal(b, &m)c.JSON(http.StatusOK, m)
})

3.4 获取 path 参数

       请求的参数通过URL路径传递,例如:/user/search/小王子/沙河。获取请求URL路径中的参数的方式如下:

func main() {//Default返回一个默认的路由引擎r := gin.Default()r.GET("/user/search/:username/:address", func(c *gin.Context) {username := c.Param("username")address := c.Param("address")//输出json结果给调用方c.JSON(http.StatusOK, gin.H{"message":  "ok","username": username,"address":  address,})})r.Run(":8080")
}c.Param()c.DefaultParam()

3.5 参数绑定

       为了可以更方便的获取请求相关参数,提高开发效率,我们可以基于请求的 Content-Type 识别请求数据类型并利用反射机制自动提取请求中 QueryString、form 表单、JSON、XML等参数到结构体中,我们可以使用 .ShouldBind() 函数来进行强大的功能,他能够基于请求自动提取 JSON、form表单和QueryString 类型的数据,并把值绑定到指定的结构体对象。

// Binding from JSON
type Login struct {User     string `form:"user" json:"user" binding:"required"`Password string `form:"password" json:"password" binding:"required"`
}func main() {router := gin.Default()// 绑定JSON的示例 ({"user": "q1mi", "password": "123456"})router.POST("/loginJSON", func(c *gin.Context) {var login Loginif err := c.ShouldBind(&login); err == nil {fmt.Printf("login info:%#v\n", login)c.JSON(http.StatusOK, gin.H{"user":     login.User,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})// 绑定form表单示例 (user=q1mi&password=123456)router.POST("/loginForm", func(c *gin.Context) {var login Login// ShouldBind()会根据请求的Content-Type自行选择绑定器if err := c.ShouldBind(&login); err == nil {c.JSON(http.StatusOK, gin.H{"user":     login.User,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})// 绑定QueryString示例 (/loginQuery?user=q1mi&password=123456)router.GET("/loginForm", func(c *gin.Context) {var login Login// ShouldBind()会根据请求的Content-Type自行选择绑定器if err := c.ShouldBind(&login); err == nil {c.JSON(http.StatusOK, gin.H{"user":     login.User,"password": login.Password,})} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})// Listen and serve on 0.0.0.0:8080router.Run(":8080")
}

ShouldBind 会按照下面的顺序解析请求中的数据进行绑定:

  1. 如果是 GET 请求,只使用 Form 绑定引擎(query)。
  2. 如果是 POST 请求,首先检查 content-type 是否为 JSON 或 XML,然后再使用Form(form-data)

四、文件上传

4.1 单个文件上传

文件上传前端页面代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head><title>上传文件示例</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="f1"><input type="submit" value="上传">
</form>
</body>
</html>

后端 gin 框架部分代码:

func main() {router := gin.Default()// 处理multipart forms提交文件时默认的内存限制是32 MiB// 可以通过下面的方式修改// router.MaxMultipartMemory = 8 << 20  // 8 MiBrouter.POST("/upload", func(c *gin.Context) {// 单个文件file, err := c.FormFile("f1")if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}log.Println(file.Filename)dst := fmt.Sprintf("C:/tmp/%s", file.Filename)// 上传文件到指定的目录c.SaveUploadedFile(file, dst)c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("'%s' uploaded!", file.Filename),})})router.Run()
}

4.2 多个文件上传

五、重定向

5.1 HTTP重定向

r.GET("/test", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
})

5.2 路由重定向

r.GET("/test", func(c *gin.Context) {// 指定重定向的URLc.Request.URL.Path = "/test2"r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"hello": "world"})
})

六、Gin路由

6.1 普通路由

6.2 路由组

七、Gin中间件

       我感觉这个中间件有点像C++回调函数。Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。

7.1 定义中间件

Gin中的中间件必须是一个 gin.HandlerFunc 类型的。

// StatCost 是一个统计耗时请求耗时的中间件
func StatCost() gin.HandlerFunc {return func(c *gin.Context) {start := time.Now()c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值// 调用该请求的剩余处理程序c.Next()// 不调用该请求的剩余处理程序// c.Abort()// 计算耗时cost := time.Since(start)log.Println(cost)}
}

7.2 注册中间件

func main() {// 新建一个没有任何默认中间件的路由r := gin.New()// 注册一个全局中间件r.Use(StatCost())r.GET("/test", func(c *gin.Context) {name := c.MustGet("name").(string) // 从上下文取值log.Println(name)c.JSON(http.StatusOK, gin.H{"message": "Hello world!",})})r.Run()
}
// 给/test2路由单独注册中间件(可注册多个)r.GET("/test2", StatCost(), func(c *gin.Context) {name := c.MustGet("name").(string) // 从上下文取值log.Println(name)c.JSON(http.StatusOK, gin.H{"message": "Hello world!",})})
shopGroup := r.Group("/shop", StatCost())
{shopGroup.GET("/index", func(c *gin.Context) {...})...
}shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{shopGroup.GET("/index", func(c *gin.Context) {...})...
}

7.3 中间件注意事项

7.3.1 gin 默认中间件

gin.Default()默认使用了LoggerRecovery中间件,其中:

  • Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release
  • Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。

如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由

7.3.2 gin 中间件中使用 goroutine 

       当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。

http://www.lryc.cn/news/461588.html

相关文章:

  • AI大模型带来哪些创业机遇?
  • [Linux] 层层深入理解文件系统——(3)磁盘组织存储的文件
  • Apache Cordova学习计划
  • Unity学习日志-API
  • Java基础常见面试题总结(上)
  • 4 -《本地部署开源大模型》在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型
  • 本地如何使用Pycharm连接远程服务器调试torchrun
  • Visual Studio 2022常用快捷键
  • mysql innodb 引擎如何直接复制数据库文件?
  • python中的global和nonlocal关键字以及闭包和模块
  • LabVIEW风机滚动轴承监测系统
  • 第1节 什么是鸿蒙系统
  • CentOS 7 将 YUM 源更改为国内镜像源
  • python调用dircmp进行文件夹比较
  • 微信小程序 - 供应链系统设计
  • 嵌入式学习-IO进程-Day03
  • docker安装elasticsearch和ik分词器
  • |智能门票|008_django基于Python的智能门票设计与实现2024_i16z2v70
  • QFramework v1.0 使用指南 更新篇:20240919. 新增 BindableDictionary
  • vue实现文件预览和文件上传、下载、预览——多图、模型、dwg图纸、文档(word、excel、ppt、pdf)
  • 探讨人工智能领域所需学习的高等数学知识及其应用场景,涵盖了微积分、线性代数、概率论等多个数学分支。
  • 详解安卓和IOS的唤起APP的机制,包括第三方平台的唤起方法比如微信
  • 服务器数据恢复—raid5阵列中多块硬盘离线导致崩溃的数据恢复案例
  • 《深度学习》OpenCV FisherFaces算法人脸识别 原理及案例解析
  • 基于Python+Flask的天气预报数据可视化分析系统(源码+文档)
  • 深入解析 Flutter兼容鸿蒙next全体生态的横竖屏适配与多屏协作兼容架构
  • 【Spring】Spring实现加法计算器和用户登录
  • 电脑d盘不见了怎么恢复?
  • 电子商务网站维护技巧:保持WordPress、主题和插件的更新
  • 交叉编译--目标平台aarch64 ubuntu 22.04