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

(Go Gin)Gin学习笔记(五)会话控制与参数验证:Cookie使用、Sessions使用、结构体验证参数、自定义验证参数

1. Cookie介绍

  • HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出
  • Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思
  • Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求
  • Cookie由服务器创建,并发送给浏览器,最终由浏览器保存

1.1 Cookie的用途

  • 测试服务端发送cookie给客户端,客户端请求时携带cookie

1.2 Cookie的使用

  • 测试服务端发送cookie给客户端,客户端请求时携带cookie
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 局部中间件r.GET("/demo", func(c *gin.Context) {// 获得内容res, err := c.Cookie("demo")// 如果没有获得cookie,err则会接收到除nil以外的内容;if err != nil {res = "noSet"// 当不存在cookie,则存储c.SetCookie("demo", "弄他", 3600, "", "", false, false)}c.JSON(200, gin.H{"cookie:": res})})r.Run(":8080")
}

SetCookie() 函数内部:

func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {if path == "" {path = "/"}http.SetCookie(c.Writer, &http.Cookie{Name:     name,Value:    url.QueryEscape(value),MaxAge:   maxAge,Path:     path,Domain:   domain,SameSite: c.sameSite,Secure:   secure,HttpOnly: httpOnly,})
}
  • name:cookie的键
  • value:cookie的值
  • maxAge:存储cookie最大的时间(seconds)
  • path:cookie详细路径
  • domain:域名
  • secure:是否支持能通过https访问
  • httpOnly:是否允许别人通过js获取自己的cookie

函数内部调用的是http包下的SetCookie()方法

并且,path为空情况下,详细路径默认是根目录

func SetCookie(w ResponseWriter, cookie *Cookie) {if v := cookie.String(); v != "" {w.Header().Add("Set-Cookie", v)}
}

可以看到内部,是在请求头中添加了Set-Cookie属性,为它进行了设置

1.3 小练习

package main import ("github.com/gin-gonic/gin""math/rand""net/http""strconv""time"
)func handler() gin.HandlerFunc {return func(c *gin.Context) {_, err := c.Cookie("token")if err != nil {return}}
}func main() {r := gin.Default()// 设置cookier.GET("/login", func(c *gin.Context) {rand.NewSource(time.Now().UnixNano())cook := strconv.Itoa(rand.Int())c.SetCookie("token", cook, 86400, "/", "localhost", false, true)c.JSON(200, gin.H{"msg": "success"})})// 检查登录r.GET("/home", handler(), func(c *gin.Context) {cookie, err := c.Cookie("token")if err != nil {c.JSON(http.StatusBadRequest, gin.H{"msg": http.StatusBadRequest})return}c.JSON(200, gin.H{"msg": cookie})})r.Run(":8080")
}

1.4 Cookie的缺点

  • 不安全,明文
  • 增加带宽消耗
  • 可以被禁用
  • cookie有上限

1. Sessions

gorilla/sessions为自定义session后端提供cookie和文件系统session以及基础结构。

主要功能是:

  • 简单的API:将其用作设置签名(以及可选的加密)cookie的简便方法。
  • 内置的后端可将session存储在cookie或文件系统中。
  • Flash消息:一直持续读取的session值。
  • 切换session持久性(又称“记住我”)和设置其他属性的便捷方法。
  • 旋转身份验证和加密密钥的机制。
  • 每个请求有多个session,即使使用不同的后端也是如此。
  • 自定义session后端的接口和基础结构:可以使用通用API检索并批量保存来自不同商店的session。

代码:

package mainimport ("fmt""net/http""github.com/gorilla/sessions"
)// 初始化一个cookie存储对象
// something-very-secret应该是一个你自己的密匙,只要不被别人知道就行
var store = sessions.NewCookieStore([]byte("something-very-secret"))func main() {http.HandleFunc("/save", SaveSession)http.HandleFunc("/get", GetSession)err := http.ListenAndServe(":8080", nil)if err != nil {fmt.Println("HTTP server failed,err:", err)return}
}func SaveSession(w http.ResponseWriter, r *http.Request) {// Get a session. We're ignoring the error resulted from decoding an// existing session: Get() always returns a session, even if empty.// 获取一个session对象,session-name是session的名字session, err := store.Get(r, "session-name")if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}// 在session中存储值session.Values["foo"] = "bar"session.Values[42] = 43// 保存更改session.Save(r, w)
}
func GetSession(w http.ResponseWriter, r *http.Request) {session, err := store.Get(r, "session-name")if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}foo := session.Values["foo"]fmt.Println(foo)
}

3. 结构体验证

gin自带了数据验证的功能,可以不用解析数据,减少if else,在代码观赏性上会好看很多

package mainimport ("fmt""github.com/gin-gonic/gin""time"
)type Person struct {//不能为空并且大于10Age      int       `form:"age" binding:"required,gt=10"`Name     string    `form:"name" binding:"required"`Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}func main() {r := gin.Default()// // 检查登录r.GET("/home", func(c *gin.Context) {var person Personif err := c.ShouldBind(&person); err != nil {c.String(500, fmt.Sprint(err))return}c.String(200, fmt.Sprintf("%#v", person))})r.Run(":8080")
}
  • Age int `form:“age” binding:“required,gt=10”

    binding标签属性就表示验证内容

    • required——必填
    • gt——值必须大于xx

    存在多个验证器时,应当以 “ , ” 隔开

验证器说明示例
-忽略字段binding:“-”
required必填字段binding:“required”
min最小长度binding:“min=10”
max最大长度binding:“max=10”
|binding:“rgb”
structonly如果有嵌套,可以决定只验证结构体上的binding:“structonly”
omitempty省略空,如果为空,则不会继续验证该字段上其他的规则,只有不为空才会继续验证其他的
len长度binding:“len=10”
eq等于binding:“eq=10”
ne不等于binding:“ne=10”
gt大于binding:“gt=10”
lt小于binding:“lt=10”
lte小于等于binding:“lte=10”
eqfield等于其他字段的值Password string binding:"eqfield=ConfirmPassword"
nefield不等于其他字段的值
eqcsfield类似eqfield,它会验证相对于顶层结构提供的字段binding:"eqcsfield = InnerStructField.Field
url字符串值包含有效的网址,必须包含http://等
uri字符串值包含有效的uri. 它将接受golang请求uri接受的任何uri
alpha字符串值仅包含字母字符
alphanum字符串值仅包含字母数字字符
numeric字符串值包含基本数字值。基本不包括指数等…
email字符串值包含有效的电子邮件
contains字符串值包含子字符串值contains=@
excludes字符串值不包含子字符串值excludes = @
containsany包含所有containsany =!@#?
excluderune字符串值不包含提供的符号excluderune = @

注意:gt、gte、lt、lte等都可以用于时间的比较,后面不需要跟值,直接binding:“gt”,表示大于当前utc时间

4. 自定义验证

package mainimport ("net/http""reflect""github.com/gin-gonic/gin""github.com/gin-gonic/gin/binding""gopkg.in/go-playground/validator.v8"
)/*对绑定解析到结构体上的参数,自定义验证功能比如我们要对 name 字段做校验,要不能为空,并且不等于 admin ,类似这种需求,就无法 binding 现成的方法需要我们自己验证方法才能实现 官网示例(https://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Custom_Functions)这里需要下载引入下 gopkg.in/go-playground/validator.v8
*/
type Person struct {Age int `form:"age" binding:"required,gt=10"`// 2、在参数 binding 上使用自定义的校验方法函数注册时候的名称Name    string `form:"name" binding:"NotNullAndAdmin"`Address string `form:"address" binding:"required"`
}// 1、自定义的校验方法
func nameNotNullAndAdmin(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {if value, ok := field.Interface().(string); ok {// 字段不能为空,并且不等于  adminreturn value != "" && !("5lmh" == value)}return true
}func main() {r := gin.Default()// 3、将我们自定义的校验方法注册到 validator中if v, ok := binding.Validator.Engine().(*validator.Validate); ok {// 这里的 key 和 fn 可以不一样最终在 struct 使用的是 keyv.RegisterValidation("NotNullAndAdmin", nameNotNullAndAdmin)}/*curl -X GET "http://127.0.0.1:8080/testing?name=&age=12&address=beijing"curl -X GET "http://127.0.0.1:8080/testing?name=lmh&age=12&address=beijing"curl -X GET "http://127.0.0.1:8080/testing?name=adz&age=12&address=beijing"*/r.GET("/5lmh", func(c *gin.Context) {var person Personif e := c.ShouldBind(&person); e == nil {c.String(http.StatusOK, "%v", person)} else {c.String(http.StatusOK, "person bind err:%v", e.Error())}})r.Run()
}

5. ❤️GoGin框架——前文链接

Gin框架学习参考网站:gin框架·Go语言中文文档

  • (Go Gin)基于Go的WEB开发框架,GO Gin是什么?怎么启动?本文给你答案
  • (Go Gin)Gin学习笔记(二):路由配置、基本路由、表单参数、上传单个文件、上传多个文件、浅扒路由原理
  • (Go Gin)Gin学习笔记(三):数据解析和绑定,结构体分析,包括JSON解析、form解析、URL解析,区分绑定的Bind方法
  • (Go Gin)Gin学习笔记(四):数据渲染、返回JSON、浅.JSON()源码、中间件、Next()方法

6. 💕👉博客专栏

  • Golang专栏-包含基础、Gin、Goam等知识
  • 云原生专栏-包含k8s、docker等知识
  • 从0开始学习云计算-华为HCIP证书
  • JUC专栏-带你快速领悟JUC的知识!
  • JVM专栏-深入Java虚拟机,理解JVM的原理
  • 基于Java研究 数据结构与算法-包含贪心算法、加权图、最短路径算法等知识
  • Docker专栏-上手热门容器技术Docker
  • SpringBoot专栏-学习SpringBoot快速开发后端
  • 项目管理工具的学习-设计技术:Maven、Git、Gradle等相关管理工具
  • JavaSE-全面了解Java基础
  • JS专栏-使用JS作的一部分实例~
  • 使用CSS所作的一部分案例
http://www.xdnf.cn/news/231157.html

相关文章:

  • 自动驾驶-一位从业两年的独特视角
  • 2025年-redis(p1-p10)
  • Kotlin与Jetpack Compose的详细使用指南
  • 高级java每日一道面试题-2025年4月30日-基础篇[反射篇]-如何防止你的类被通过反射非法实例化?
  • PCI总线数据采集卡 32路多功能异步模拟量信号采集卡
  • 如何在 Go 中实现各种类型的链表?
  • 硬盘分区丢失≠末日!3步逻辑恢复法+物理修复全流程图解
  • 大数据应用开发和项目实战-Seaborn
  • 使用通义千问大模型做结构化输出报错的分析
  • ubantu部署yolov5(第四集:模型加速)
  • 正点原子STM32H743单片机实现ADC多通道检测
  • k8s平台:手动部署Grafana
  • SQL命令二:SQL 高级查询与特殊算法
  • Git从入门到精通-第一章-基础概念
  • 软件性能测试有多关键?能找出潜在问题并确保其顺利运行吗?
  • [250430] Kali Linux 存储库密钥丢失导致所有用户无法正常更新 APT
  • JavaScript:从JS的执行机制到location对象
  • 大语言模型(LLM)应用开发平台Dify详细使用
  • 系统思考:局部最优与全局失衡
  • WHAT - Tailwind CSS + Antd = MetisUI组件库
  • GEO vs SEO:从搜索引擎到生成引擎的优化新思路
  • vs2019 调试看不到std::list 中的值,
  • 上班无聊用python写一个摸鱼小游戏:数字碰撞
  • conda管理python环境
  • 2025年渗透测试面试题总结-拷打题库28(题目+回答)
  • 前端跨域问题详解:原因、解决方案与最佳实践
  • Doris索引机制全解析,如何用高效索引加速数据分析
  • PCB设计工艺规范(一)概述
  • 树莓派智能摄像头实战指南:基于TensorFlow Lite的端到端AI部署
  • Docker进入MySQL之后如何用sql文件初始化数据