目录
一、请求路由
1.多种请求类型
2.静态文件夹
3.参数作为URL
4.泛绑定:
二、获取请求参数
1.获取GET请求参数
2.获取POST请求参数
3.获取Body值
4.获取参数绑定结构体
三、验证请求参数
1.结构体验证
2.自定义验证
3.升级验证-支持多语言错误信息
四、中间件
1.使用gin中间件
(1)gin.Logger()中间件
(2)Recovery()中间件
2.自定义ip白名单中间件
五、基础拓展
1.优雅关停
2.模板渲染
3.自动证书配置
主要包括"get" "put" "post" "delete"等八种请求类型
r := gin.Default()
//GET(路由,回调方法) 回调方法返回的内容是一个字符串
r.GET("/get",func(c *gin.Context){
c.String(200,"get")
})
//有个Any方法,可以设置多种请求类型打到相同的路由下面
//Any方法里面支持八种请求类型,基本上覆盖了http所有的请求方法
r.Any("/any",func(c *gin.Context){
c.String(200,"any")
})
可以把gin当作静态服务器来使用
/*
设置静态文件夹绑定:r.Static(路由,静态文件夹)
另外一种写法:r.StaticFS("/static"路由,http.Dir("static")资源)
设置单个静态文件: r.StaticFile(路由,资源)
*/
r.Static("/assets","./assets")
r.StaticFS("/static",http.Dir("static"))
r.StaticFile("/favicon.ico","./favicon.ico")
在对应位置设置静态文件夹。
r.GET(...)方法创建一个Get路由,这里面设置一下获取name的url参数,再设置下获取id的url参数,再设置它的回调参数,返回的内容使用json。
返回值是200,返回内容是gin.H{}就是一个map结构
测试:
第一个参数是name,第二个参数是id。
结果和传入的参数值相同,输出格式是json
所有前缀的请求都定向到一个资源中,类似nginx的前缀匹配
泛绑定和普通用法的区别在于前缀的匹配,所有的匹配都会打到相同的方法上。
所有/user前缀的请求都会打到hello world上来。
(补充:
post是通过HTTPpost机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。)
r := gin.Default()
//r.GET(...)方法创建一个gin的路由,定义一个/test的路由
r.GET("/test",func(c *gin.Context){
/*
回调方法两个参数firstName, lastName.
firstName是一个不带默认值的参数,lastName获取默认数据,第一个是参数的名称,第二个是设置的默认值。*/
firstName := c.Query("first_name")
lastName := c.DefaultQuery("last_name","last_default_name")
//c.String(...)以string的方式输出这个值
c.String(http.StatusOK,"%s,%s",firstName,lastName)
})
firstName := ctx.PostForm("first_name")
lastName := ctx.DefaultPostForm("last_name","default_last_name")
这里的body一般是指body row之类的数据流请求,可能是结构化的数据,也可能是port buffer之类的数据
//要拿到body的内容,要借助ioutil.ReadAll()方法,参数为默认的request里面的body数据流。返回一个字节数组和error
r.POST("/test", func(c *gin.Context){
bodyBytes, err := ioutil.ReadAll(c.Request.Body)
if err != nil{
c.String(http.StatusBadRequest, err.Error())
//c.Abort()直接让输出结束
c.Abort()
}
c.String(http.StatusOK,string(bodyBytes))
})
这是gin的核心功能
构想是想用post和get同时访问到一个相同的回调方法里,接收到的参数都是一个结构体
如果是post请求,根据post请求的参数值转化为这个结构体。
如果是get请求,根据get请求的参数值转化为这个结构体。
//定义结构体,有三项内容 后面加上tag`...` form意思是请求参数可以通过这个结构体进行转换,由参数转变为结构体。
type Person struct{
Name string `form:"name"`
Address string `form:"address"`
Birthday time.Time `form:"birthday"`
}
func main(){
r := gin.Default()
r.GET("/testing",testing)
r.POST("/testing",testing)
}
func testing(c *gin.Context){
var person Person
//开始对数据进行binding操作
//使用ShouldBind()这个方法,接收interface类型参数,返回的值是err
//实际上这一步不管get还是post,会根据请求类型的contentType动态解释相应的请求的数据的格式到这个结构体里面。如,get就直接可以识别 name = 某个值&address=某个值...
//post就可以直接从formdata里面拿,如果我们请求的是json,就可以直接从json中解析出这个数据。
//总之,ShouldBind()里面,能考虑到的格式都已经兼容了,前提是header里面必须要传content-type
if err := c.ShouldBind(&person); err == nil{
c.String(200,"%v",person)
}else{
c.String(200,"person bind error:%v",err)
}
}
一般将验证规则定义到结构体的tag上面进行验证
type Person struct{
Age int `form:"age" binding:"required,gt=10"`
Name string `form:"name" binding:"required"`
Address string `form:"address" binding:"required"`
}
func main(){
r := gin.Default()
r.GET("/testing",func(c *gin.Context){
var person Person
if err := c.ShouldBind(&person);err != nil{
c.String(500,"%v",err)
}
c.String(200,"%v",person)
})
r.Run()
}
其他验证规则参考官方gopkg文档
gin默认封装的规则是基于这个validator.v8来使用的。
validator.v8官网
多个验证之间用逗号分隔
验证 | 例子 |
或的验证 | | |
存在的验证 | exists |
支持非空 | omitempty |
支持slice验证,并且slice可以是二维数组 |
dive |
必传和字段长度的验证 |
required, len=10 |
最大最小值验证 |
max=10, min=10 |
等于和不等于某值的验证 |
eq=10, ne=10 |
大于某值,小于某值 |
gt=10, lt=10 |
小于等于某值 |
lte=10 |
字段比对相同值的验证 |
1.eqfiled=ConfirmPassword 2.validate.FieldWithValue(password,confirmpassword,"eqfield") 3.eqcsfield=InnerStructField.Field |
一些字符串验证的例子:只包含字母、数字等 |
1.只包含字母:alpha 2.只包含字母和数字:alphanum 3.只包含数字:numeric |
结构体验证不能满足要求时,需要自定义规则
根据请求的语言进行错误信息转换
中间件是介于gin服务器和回调函数执行的一个中间层,它可以用来做请求拦截和日志打印
使用gin.Default()方法创建gin实例,gin.Default()里会默认实现两个中间件Logger()和Recovery()
作用是在请求的时候会在控制台打印一行请求地址的url和耗时等信息
会输出状态码200,执行的时间、ip、请求方法、路由
如果想把错误打印到文件,需要设置下gin.Logger()打印的位置
gin.DefaultWriter = io.MuilWriter(f)把日志信息输出到f文件中
gin.DefaultErrorWriter = io.MuilWriter(f)把错误信息也输出到f文件中
控制台中不再输出,输出在gin.log文件中
当代码里面有一个panic,如果没有使用Recovery()中间件,这个GET请求会报错,以至于传到main里面会报错,这个服务就断掉了。但是使用了Recovery就会捕获掉这个错误,不至于导致进程去挂掉。
(1).首先创建文件夹middelware_whitelist和main.go文件
(2).创建gin实例
(3).定义一个对应的中间件,去use。在use之前,先把原来的请求路由设置一下。
(4).参考Logger()和recover()中间件的实现,返回HandlerFunc
定义白名单放到一个数组里ipList,实际上应该放到配置文件里面,每次用的时候再进行提取
(5).设置一个flag标签,默认为false
(6).遍历ip列表,它的比对对象是client的一个数据,client又是我们当前访问者的ip
是指服务器处理时如果未处理完毕,会有一个超时等待时间去完成后续的一个处理,保证服务不在中间中断停止
在前后端不分离之前的一个概念是比较火的。主要是说数据的后端,可以将数据与html混合到一起输出。
是指无需配置任何证书,即可自动下载证书。过期之后还可以自动续约的证书的功能