做网站注意哪些,西安哪家网络优化好,网站建设教程免费湖南岚鸿,佛山专业网站建设公司推荐【Go学习】04-1-Gin框架 初识框架go流行的web框架GinirisBeegofiber Gin介绍Gin快速入门 路由RESTful API规范请求方法URI静态url路径参数模糊匹配 处理函数分组路由 请求参数GET请求参数普通参数数组参数map参数 POST请求参数表单参数JSON参数 路径参数文件参数 响应字符串方式… 【Go学习】04-1-Gin框架 初识框架go流行的web框架GinirisBeegofiber Gin介绍Gin快速入门 路由RESTful API规范请求方法URI静态url路径参数模糊匹配 处理函数分组路由 请求参数GET请求参数普通参数数组参数map参数 POST请求参数表单参数JSON参数 路径参数文件参数 响应字符串方式JSON方式XML方式文件方式设置http响应头重定向YAML方式 初识框架
框架是一系列工具的集合能让开发变的便捷。
学习框架的目的就是为了提供项目的开发效率使我们更加专注业务而不是和业务无关的底层代码。
go流行的web框架
如果学习过其他语言可能知道Java用的比较多的是Spring框架PHP用的比较多的是Laravelpython用的多的是Django都在各自的语言中具有强大的统治力。
go从诞生之初就带有浓重的开源属性其原生库已经很强大即使不依赖框架也能进行高性能开发又因为其语言并没有一定的设计标准所以较为灵活也就诞生了众多的框架各具有特色满足不同的喜好。
Gin
地址https://github.com/gin-gonic/gin
号称最快的go语言web框架目前是go官方的推荐框架https://go.dev/doc/tutorial/。
iris
地址https://github.com/kataras/iris
性能比gin高一些支持MVC但这款框架评价不太好使用上问题较多近些年很少去选择使用
Beego
地址https://github.com/beego/beego
国人开发最早的go web框架之一工具集比较完善性能较差据传言作者是php转行所以框架带有浓厚的php特色早期国内使用的多目前少有人选择。
fiber
地址https://github.com/gofiber/fiber
2020年发布的框架发展迅速建立在fasthttp之上性能目前最高受Express启发比较简洁上手较快和gin类似。 当然还有其他一些框架但从star数上以及流行程度上看gin一骑绝尘gin的好处在于其简洁扩展性稳定性以及性能都比较出色。 go的框架其实是可以理解为库并不是用了某一个框架就不能用别的框架可以选择性的使用各个库中的优秀组件进行组合。
Gin介绍
特性 快速 基于 Radix 树的路由小内存占用。没有反射。可预测的 API 性能。 支持中间件 传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如LoggerAuthorizationGZIP最终操作 DB。 Crash 处理 Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样你的服务器将始终可用。例如你可以向 Sentry 报告这个 panic JSON 验证 Gin 可以解析并验证请求的 JSON例如检查所需值的存在。 路由组 更好地组织路由。是否需要授权不同的 API 版本…… 此外这些组可以无限制地嵌套而不会降低性能。 错误管理 Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终中间件可以将它们写入日志文件数据库并通过网络发送。 内置渲染 Gin 为 JSONXML 和 HTML 渲染提供了易于使用的 API。 可扩展性 新建一个中间件非常简单。
Gin快速入门
go版本需求go1.13及以上
环境windows 11
# 创建工作区
F:\Code\Golang\TuLing\workPathmkdir ginlearn
F:\Code\Golang\TuLing\workPathcd ginlearn
# 初始化工作区
F:\Code\Golang\TuLing\workPath\ginlearngo work init# 创建模块
F:\Code\Golang\TuLing\workPath\ginlearnmkdir helloworld
F:\Code\Golang\TuLing\workPath\ginlearncd helloworld
# 初始化模块
F:\Code\Golang\TuLing\workPath\ginlearn\helloworldgo mod init test.com/helloworld
go: creating new go.mod: module test.com/helloworld
F:\Code\Golang\TuLing\workPath\ginlearn\helloworldcd ..# 将模块加入工作区
F:\Code\Golang\TuLing\workPath\ginlearngo work use ./helloworld使用goland打开 下载gin
PS F:\Code\Golang\TuLing\workPath\ginlearn cd .\helloworld\
PS F:\Code\Golang\TuLing\workPath\ginlearn\helloworld go get -u github.com/gin-gonic/gin示例程序创建main.go
package mainimport github.com/gin-gonic/ginfunc 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 上启动服务
}运行后apifox进行测试 符合预期这样简单的代码就实现了一个http的服务
路由
路由是URI到函数的映射。
一个URI含: http://localhost:8080/user/find?id11
协议比如httphttps等ip端口或者域名比如127.0.0.1:8080或者www.test.compath比如 /pathquery比如 ?query
同时访问的时候还需要指明HTTP METHOD比如 GET GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据. POST POST方法用于将实体提交到指定的资源通常会导致在服务器上的状态变化 HEAD HEAD方法请求一个与GET请求的响应相同的响应但没有响应体. PUT PUT方法用请求有效载荷替换目标资源的所有当前表示 DELETE DELETE方法删除指定的资源 CONNECT CONNECT方法建立一个到由目标资源标识的服务器的隧道。 OPTIONS OPTIONS方法用于描述目标资源的通信选项。 TRACE TRACE方法沿着到目标资源的路径执行一个消息环回测试。 PATCH PATCH方法用于对资源应用部分修改。 使用的时候应该尽量遵循其语义 RESTful API规范
RESTful API 的规范建议我们使用特定的HTTP方法来对服务器上的资源进行操作。
比如
GET表示读取服务器上的资源POST表示在服务器上创建资源PUT,表示更新或者替换服务器上的资源DELETE表示删除服务器上的资源PATCH表示更新/修改资源的一部分
请求方法
r.GET(/get, func(ctx *gin.Context) {ctx.JSON(200, get)
})
r.POST(/post, func(ctx *gin.Context) {ctx.JSON(200, post)
})
r.DELETE(/delete, func(ctx *gin.Context) {ctx.JSON(200, delete)
})
r.PUT(/put, func(ctx *gin.Context) {ctx.JSON(200, put)
})如果想要支持所有
r.Any(/any, func(ctx *gin.Context) {ctx.JSON(200, any)
})如果想要支持其中的几种
r.GET(/hello, func(ctx *gin.Context) {//数组 map list 结构体ctx.JSON(200, gin.H{name: hello world,})
})
r.POST(/hello, func(ctx *gin.Context) {//数组 map list 结构体ctx.JSON(200, gin.H{name: hello world,})
})URI
URI书写的时候我们不需要关心scheme和authority这两部分我们主要通过path和query两部分的书写来进行资源的定位。
静态url
比如/hello/user/find
r.POST(/user/find, func(ctx *gin.Context) {
})路径参数
比如/user/find/:id
r.POST(/user/find/:id, func(ctx *gin.Context) {param : ctx.Param(id)ctx.JSON(200, param)
})模糊匹配
比如/user/*path
r.POST(/user/*path, func(ctx *gin.Context) {param : ctx.Param(path)ctx.JSON(200, param)
})处理函数
定义
type HandlerFunc func(*Context)通过上下文的参数获取http的请求参数响应http请求等。
分组路由
在进行开发的时候我们往往要进行模块的划分比如用户模块以user开发商品模块以goods开头。
或者进行多版本开发不同版本之间路径是一致的这种时候就可以用到分组路由了。
比如
ug : r.Group(/user)
{ug.GET(find, func(ctx *gin.Context) {ctx.JSON(200, user find)})ug.POST(save, func(ctx *gin.Context) {ctx.JSON(200, user save)})
}
gg : r.Group(/goods)
{gg.GET(find, func(ctx *gin.Context) {ctx.JSON(200, goods find)})gg.POST(save, func(ctx *gin.Context) {ctx.JSON(200, goods save)})
}请求路径则为
[GIN-debug] GET /user/find -- main.main.func2 (3 handlers)
[GIN-debug] POST /user/save -- main.main.func3 (3 handlers)
[GIN-debug] GET /goods/find -- main.main.func4 (3 handlers)
[GIN-debug] POST /goods/save -- main.main.func5 (3 handlers)请求参数
GET请求参数
使用Get请求传参时类似于这样
http://localhost:8080/user/save?id11namezhangsan如何获取呢
普通参数
request url: http://localhost:8080/user/save?id11namezhangsan Query匹配字段 r.GET(/user/save, func(ctx *gin.Context) {id : ctx.Query(id)name : ctx.Query(name)ctx.JSON(200, gin.H{id: id,name: name,})
})如果参数不存在就给一个默认值 DefaultQueryquery为空时回返回个默认值 r.GET(/user/save, func(ctx *gin.Context) {id : ctx.Query(id)name : ctx.Query(name)address : ctx.DefaultQuery(address, 北京)ctx.JSON(200, gin.H{id: id,name: name,address: address,})
})GetQuery多了个query成功与否的返回值 r.GET(/user/save, func(ctx *gin.Context) {id, ok : ctx.GetQuery(id)address, aok : ctx.GetQuery(address)ctx.JSON(200, gin.H{id: id,idok: ok,address: address,aok: aok,})
})id是数值类型上述获取的都是string类型根据类型获取通过form进行字段匹配 BindQuery与结构体字段进行匹配 type User struct {Id int64 form:idName string form:name
}
r.GET(/user/save, func(ctx *gin.Context) {var user Usererr : ctx.BindQuery(user)if err ! nil {log.Println(err)}ctx.JSON(200, user)
})ShouldBindQuery有binding字段的要求必填否则报错 r.GET(/user/save, func(ctx *gin.Context) {var user Usererr : ctx.ShouldBindQuery(user)if err ! nil {log.Println(err)}ctx.JSON(200, user)
})区别 当bind是必须的时候ShouldBindQuery会报错开发者自行处理状态码不变。 type User struct {Id int64 form:idName string form:nameAddress string form:address binding:required
}BindQuery则报错的同时会将状态码改为400。所以一般建议是使用Should开头的bind。
数组参数
请求urlhttp://localhost:8080/user/save?addressBeijingaddressshanghai QueryArray重复查询字段组装成数组 r.GET(/user/save, func(ctx *gin.Context) {address : ctx.QueryArray(address)ctx.JSON(200, address)
})GetQueryArray多成功与否返回值 r.GET(/user/save, func(ctx *gin.Context) {address, ok : ctx.GetQueryArray(address)fmt.Println(ok)ctx.JSON(200, address)
})ShouldBindQuery r.GET(/user/save, func(ctx *gin.Context) {var user Usererr : ctx.ShouldBindQuery(user)fmt.Println(err)ctx.JSON(200, user)
})但是这样的话我们的user的address要求就是个数组 type User struct {Id int64 form:idName string form:nameAddress []string form:address binding:required
}成功返回 {Id: 0,Name: ,Address: [Beijing,shanghai]
}map参数
请求urlhttp://localhost:8080/user/save?addressMap[home]BeijingaddressMap[company]shanghai QueryMap组装成map r.GET(/user/save, func(ctx *gin.Context) {addressMap : ctx.QueryMap(addressMap)ctx.JSON(200, addressMap)
})GetQueryMap多成功与否返回值 r.GET(/user/save, func(ctx *gin.Context) {addressMap, _ : ctx.GetQueryMap(addressMap)ctx.JSON(200, addressMap)
})返回值 {company: shanghai,home: Beijing
}POST请求参数
post请求一般是表单参数和json参数
表单参数
r.POST(/user/save, func(ctx *gin.Context) {id : ctx.PostForm(id)name : ctx.PostForm(name)address : ctx.PostFormArray(address)addressMap : ctx.PostFormMap(addressMap)ctx.JSON(200, gin.H{id: id,name: name,address: address,addressMap: addressMap,})
})PostForm从表单中对应的字段PostFormArray从表单找对应的数组PostFormMap从表单找对应的Map
r.POST(/user/save, func(ctx *gin.Context) {var user Usererr : ctx.ShouldBind(user)addressMap, _ : ctx.GetPostFormMap(addressMap)user.AddressMap addressMapfmt.Println(err)ctx.JSON(200, user)
})GetPostFormMap从表单找对应的Map
JSON参数
json参数如下
{id:1111,name:zhangsan,address: [beijing,shanghai],addressMap:{home:beijing}
}r.POST(/user/save, func(ctx *gin.Context) {var user Usererr : ctx.ShouldBindJSON(user)fmt.Println(err)ctx.JSON(200, user)
})对应字段进行匹配
其他类型参数注入xmlyaml等和json道理一样
路径参数
请求urlhttp://localhost:8080/user/save/111
r.POST(/user/save/:id, func(ctx *gin.Context) {ctx.JSON(200, ctx.Param(id))
}):id 表示 占位符可以匹配 任意路径中的值。 ctx.Param(id) 用于 获取路径参数 id 的值。
文件参数
r.POST(/user/save, func(ctx *gin.Context) {form, err : ctx.MultipartForm()if err ! nil {log.Println(err)}files : form.Filefor _, fileArray : range files {for _, v : range fileArray {ctx.SaveUploadedFile(v, ./v.Filename)}}ctx.JSON(200, form.Value)
})在form表单中请求file类型 这样就能在本地看到了 响应
字符串方式
r.GET(/user/save, func(ctx *gin.Context) {ctx.String(http.StatusOK, this is a %s, ms string response)
})JSON方式
r.GET(/user/save, func(ctx *gin.Context) {ctx.JSON(http.StatusOK, gin.H{success: true,})
})XML方式
r.GET(/user/save, func(ctx *gin.Context) {u : XmlUser{Id: 11,Name: zhangsan,}ctx.XML(http.StatusOK, u)
})文件方式
r.GET(/user/save, func(ctx *gin.Context) {//ctx.File(./1.png)ctx.FileAttachment(./1.png, 2.png)
})设置http响应头
r.GET(/user/save, func(ctx *gin.Context) {ctx.Header(test, headertest)
})重定向
r.GET(/user/save, func(ctx *gin.Context) {ctx.Redirect(http.StatusMovedPermanently, http://www.baidu.com)
})YAML方式
r.GET(/user/save, func(ctx *gin.Context) {ctx.YAML(200, gin.H{name: ms, age: 19})
})