Golang中Gin框架的使用入门教程
来源:脚本之家
时间:2022-12-22 18:10:05 167浏览 收藏
本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《Golang中Gin框架的使用入门教程》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~
官方地址:gin-gonic.com/docs/
安装与简单测试
下载并安装Gin包,并导入引用
$ go get -u github.com/gin-gonic/gin //将gin引入到代码中 import "github.com/gin-gonic/gin" //可选。如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包 import "net/http"
编写如下测试代码
package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() // 监听并在 0.0.0.0:8080 上启动服务 }
然后在浏览器中进行测试: http://localhost:8080 就可以访问到响应的请求。
常见请求与分组请求
下面展示几种其他 常规 请求方式
// 下面列出常用几种请求方式 r.GET("/someGet", handle) r.POST("/somePost", handle) r.PUT("/somePut", handle) r.DELETE("/someDelete", handle) r.PATCH("/somePatch", handle) r.HEAD("/someHead", handle) r.OPTIONS("/someOptions", handle) r.Any("/any", handle)
**还可以对请求进行分组操作。 **
v1 := r.Group("/v1") { v1.GET("/login", handle) } v2 := r.Group("/v2") { v2.GET("/login", handle) }
下面例子 是** 获得请求中path**
func main() { router := gin.Default() // 匹配/user/john router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // 匹配/user/john/和/user/john/send 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) }) router.Run(":8080") }
/user/:name/*action : 表示对后边路由全部模糊匹配。例如:/user/john/send/1 形式 action会匹配得到 name 是 john, action是 /send/1
获取参数 与 参数合法性验证
获得query中参数
func main() { router := gin.Default() // welcome?firstname=Jane&lastname=Doe router.GET("/user", func(c *gin.Context) { firstname := c.DefaultQuery("name", "kim") // 获取query中的name,没有的话就为kim lastname := c.Query("age") // 获取query中的age c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080") }
获得multipart/urlencoded form中的参数
func main() { router := gin.Default() router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("age") nick := c.DefaultPostForm("name", "kim") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) router.Run(":8080") }
curl http://127.0.0.1:8080/form\_post -X POST -d 'name=john&age=25'
通过此curl发送post请求,即可获得表单中数据。
模型绑定和参数验证
基本用法
我们已经见识了x-www-form-urlencoded类型的参数处理,现在越来越多的应用习惯使用JSON来通信,也就是无论返回的response还是提交的request,其content-type类型都是application/json的格式。而对于一些旧的web表单页还是x-www-form-urlencoded的形式,这就需要我们的服务器能支持住这多种content-type的参数了。
由于go是静态语言,需要先实现定义数据模型,这就需要用到gin的model bind功能了。
gin使用go-playground/validator.v8验证参数,查看完整文档。
需要在绑定的字段上设置tag,比如,绑定格式为json,需要这样设置json:"fieldname" 。
此外,Gin还提供了两套绑定方法:
1.Must bind
- Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML
- Behavior - 这些方法底层使用 MustBindWith,如果存在绑定错误,请求将被以下指令中止 .
c.AbortWithError(400, err).SetType(ErrorTypeBind),
响应状态代码会被设置为400,请求头Content-Type被设置为text/plain; charset=utf-8。
注意,如果你试图在此之后设置响应代码,将会发出一个警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422,如果你希望更好地控制行为,请使用ShouldBind相关的方法
2.Should bind
- Methods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML
- Behavior - 这些方法底层使用 ShouldBindWith,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。
当我们使用绑定方法时,Gin会根据Content-Type推断出使用哪种绑定器,如果你确定你绑定的是什么,你可以使用MustBindWith或者BindingWith。
你还可以给字段指定特定规则的修饰符,如果一个字段用binding:"required"修饰,并且在绑定时该字段的值为空,那么将返回一个错误。
type Person struct { Name string `json:"name" binding:"required"` // json格式从name取值,并且该值为必须的 Age int `json:"age" binding:"required,gt=20"` // json格式从age取值,并且该值为必须的,且必须大于20 } func main() { router := gin.Default() router.POST("/test", func(context *gin.Context) { var person Person // 这里我确定传过来的一定是JSON所以用ShouldBindJSON,否则可以用ShouldBind if err := context.ShouldBindJSON(&person); err != nil { context.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } context.JSON(http.StatusOK, gin.H{ "success": true, }) }) router.Run(":8080") }
curl http://localhost:8080/test -X POST -d '{"name":"Rock","age": 25}'
上面是通过json映射方式 绑定 请求数据,并且对请求数据进行验证。
自定义参数验证
验证包 gopkg.in/go-playground/validator.v8使用方法
package main import ( "net/http" "reflect" "time" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "gopkg.in/go-playground/validator.v8" ) type Booking struct { // 这里的验证方法为bookabledate CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` // gtfield=CheckIn表示大于的字段为CheckIn CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` } func bookableDate( v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string, ) bool { // 这里有两个知识点,映射和断言 // 在这里,field是一个reflect.Type的接口类型变量,通过Interface方法获得field接口类型变量的真实类型,可以理解为reflect.Value的逆操作 // 在这里,断言就是将一个接口类型的变量转化为time.Time,前提是后者必须实现了前者的接口 // 综上,这里就是将field进行了类型转换 if date, ok := field.Interface().(time.Time); ok { today := time.Now() if today.Year() > date.Year() || today.YearDay() > date.YearDay() { 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(":8080") } 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()}) } }
上面方法自定义了一种参数验证器。
项目结构参考
├── conf #项目配置文件目录 │ └── config.toml #大家可以选择自己熟悉的配置文件管理工具包例如:toml、xml等等 ├── controllers #控制器目录,按模块存放控制器(或者叫控制器函数),必要的时候可以继续划分子目录。 │ ├── food.go │ └── user.go ├── main.go #项目入口,这里负责Gin框架的初始化,注册路由信息,关联控制器函数等。 ├── models #模型目录,负责项目的数据存储部分,例如各个模块的Mysql表的读写模型。 │ ├── food.go │ └── user.go ├── static #静态资源目录,包括Js,css,jpg等等,可以通过Gin框架配置,直接让用户访问。 │ ├── css │ ├── images │ └── js ├── logs #日志文件目录,主要保存项目运行过程中产生的日志。 └── views #视图模板目录,存放各个模块的视图模板,当然有些项目只有api,是不需要视图部分,可以忽略这个目录 └── index.html
Gin框架运行模式
为方便调试,Gin 框架在运行的时候默认是debug模式,在控制台默认会打印出很多调试日志,上线的时候我们需要关闭debug模式,改为release模式。
设置Gin框架运行模式:
通过环境变量设置 export GIN_MODE=release
GIN_MODE环境变量,可以设置为debug或者release
通过代码设置
在main函数,初始化gin框架的时候执行下面代码 // 设置 release模式 gin.SetMode(gin.ReleaseMode) // 或者 设置debug模式 gin.SetMode(gin.DebugMode)
Gin如何获取客户ip
route.GET("/ip", func(c *gin.Context) { // 获取用户IP ip := c.ClientIP() c.JSON(http.StatusBadRequest, gin.H{"ip": ip}) })
Gin处理请求结果
以String类型响应请求
func (c *Context) String(code int, format string, values ...interface{}) c.String(200,"欢迎访问%s, 你是%s", "tizi360.com!","最靓的仔!")
以Json格式响应请求
我们开发api接口的时候常用的格式就是json,下面是返回json格式数据的例子
// User 定义 type User struct { Name string `json:"name"` // 通过json标签定义struct字段转换成json字段的名字。 Email string `json:"email"` } // Handler 控制器 func(c *gin.Context) { //初始化user对象 u := &User{ Name: "tizi365", Email: "tizi@tizi365.com", } //返回json数据 //返回结果:{"name":"tizi365", "email":"tizi@tizi365.com"} c.JSON(200, u) }
以文件形式响应请求
c.FileAttachment("/var/www/1.jpg", "1.jpg")
设置http响应头
func(c *gin.Context) { //设置http响应 header, key/value方式,支持设置多个header c.Header("site","tizi365") }
Gin处理html模板
func main() { // 初始化gin对象 router := gin.Default() // 首先加载templates目录下面的所有模版文件,模版文件扩展名随意 router.LoadHTMLGlob("templates/*") // 绑定一个url路由 /index router.GET("/index", func(c *gin.Context) { // 通过HTML函数返回html代码 // 第二个参数是模版文件名字 // 第三个参数是map类型,代表模版参数 // gin.H 是map[string]interface{}类型的别名 c.HTML(http.StatusOK, "index.html", gin.H{ "title": "Main website", }) }) // 启动http服务,并且绑定在8080端口 router.Run(":8080") }
Gin访问静态资源文件
func main() { router := gin.Default() // 设置静态资源文件目录,并且绑定一个Url前缀 // 静态资源文件目录:/var/www/tizi365/assets // /assets是访问静态资源的url前缀 // 例如: // /assets/images/1.jpg 这个url文件,存储在/var/www/tizi365/assets/images/1.jpg router.Static("/assets", "/var/www/tizi365/assets") // 为单个静态资源文件,绑定url // 这里的意思就是将/favicon.ico这个url,绑定到./resources/favicon.ico这个文件 router.StaticFile("/favicon.ico", "./resources/favicon.ico") // Listen and serve on 0.0.0.0:8080 router.Run(":8080") }
Gin处理Cookie操作
package main import ( "fmt" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() // 设置cookie路由 router.GET("/setCookie", func(c *gin.Context) { // 设置cookie c.SetCookie("site_cookie", "cookievalue", 3600, "/", "localhost", false, true) }) // 获得cookie路由 router.GET("/cookie", func(c *gin.Context) { data, err := c.Cookie("/cookie") fmt.Printf(data) if err != nil { // 直接返回cookie值 c.String(200, data) return } c.String(200, "not found!") }) //删除cookie路由 router.GET("/removeCookie", func(c *gin.Context) { c.SetCookie("set_cookie", "cookievalue", -1, "/", "localhost", false, true) c.String(200, "删除cookie") }) router.Run(":8080") }
Gin文件上传
package main // 导入gin包 import ( "fmt" "github.com/gin-gonic/gin" "log" "net/http" ) func main() { router := gin.Default() // 设置文件上传大小限制,默认是32m router.MaxMultipartMemory = 64Gin中间件
在Gin框架中,中间件(Middleware)指的是可以拦截http请求-响应生命周期的特殊函数,在请求-响应生命周期中可以注册多个中间件,每个中间件执行不同的功能,一个中间执行完再轮到下一个中间件执行。
中间件的常见应用场景如下:
- 请求限速
- api接口签名处理
- 权限校验
- 统一错误处理
Gin支持设置全局中间件和针对路由分组设置中间件,设置全局中间件意思就是会拦截所有请求,针对分组路由设置中间件,意思就是仅对这个分组下的路由起作用。
package main // 导入gin包 import ( "fmt" "github.com/gin-gonic/gin" "log" "time" ) // 自定义个日志中间件 func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // 可以通过上下文对象,设置一些依附在上下文对象里面的键/值数据 c.Set("example", "12345") fmt.Printf("1. 执行中间件设置 \n") // 在这里处理请求到达控制器函数之前的逻辑 // 调用下一个中间件,或者控制器处理函数,具体得看注册了多少个中间件。 c.Next() fmt.Printf("4. 完成 执行中间件设置 \n") // 在这里可以处理请求返回给用户之前的逻辑 latency := time.Since(t) log.Print(latency) // 例如,查询请求状态吗 status := c.Writer.Status() log.Println(status) } } func main() { r := gin.New() // 注册上面自定义的日志中间件 r.Use(Logger()) r.GET("/test", func(c *gin.Context) { // 查询我们之前在日志中间件,注入的键值数据 fmt.Printf("2. 开始执行业务逻辑 \n") example := c.MustGet("example").(string) // it would print: "12345" log.Println(example) fmt.Printf("3. 业务逻辑执行完成 \n") }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") }
其输出结果如下:
1. 执行中间件设置
2. 开始执行业务逻辑
2022/10/22 16:33:29 12345
3. 业务逻辑执行完成
4. 完成 执行中间件设置
2022/10/22 16:33:29 658.681µs
2022/10/22 16:33:29 200
Gin 中间件类似 Node中的洋葱模型。
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
-
505 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
280 收藏
-
181 收藏
-
371 收藏
-
236 收藏
-
416 收藏
-
407 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 迷路的过客
- 这篇技术文章真及时,太细致了,真优秀,码起来,关注老哥了!希望老哥能多写Golang相关的文章。
- 2023-01-16 10:58:25
-
- 完美的黑猫
- 细节满满,码住,感谢博主的这篇博文,我会继续支持!
- 2023-01-16 03:33:11
-
- 洁净的悟空
- 这篇博文真是及时雨啊,师傅加油!
- 2023-01-15 17:17:27
-
- 无限的小鸭子
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢作者分享技术文章!
- 2023-01-06 14:21:59
-
- 壮观的战斗机
- 这篇文章真是及时雨啊,细节满满,真优秀,mark,关注作者大大了!希望作者大大能多写Golang相关的文章。
- 2022-12-27 17:10:47
-
- 自然的故事
- 感谢大佬分享,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢up主分享文章内容!
- 2022-12-23 07:28:37