一文了解Gin对Cookie的支持
1. 引言
本文将从Web应用程序处理请求时需要用户信息,同时HTTP又是无状态协议这个矛盾点出发。从该问题出发,简单描述了解决该问题的Token
机制,进而引出Cookie
的实现方案。
基于此我们将详细描述Cookie
的规范,然后详细描述具体的实现方式,进一步描述Gin
框架对Cookie
操作提供的API
,最终提供了一个详细的代码实现。
我们还将详细描述Gin
框架提供API
的实现原理,帮助用户更好得使用这两个API
。
2. 问题引入
在 如何使用Gin搭建一个Go Web应用程序 一文中,我们已经了解了如何使用Gin
搭建一个简单的Web应用程序。然而,在现实的Web应用程序中,大部分功能都是需要用户的身份信息才能处理。举例来说,在一个视频网站查看用户最近观看记录,如果缺少用户身份信息,此时将无法对请求进行处理。
但是HTTP协议的设计,是无状态的,也就是每次请求都是独立的。基于此,应该有一套机制,能够在用户身份认证成功后,给用户分配一个Token
,后续用户在每次请求时,都携带上该Token
,使得服务器能够从请求中获取用户信息,解决HTTP无状态问题。大概流程如下:
上面流程中,需要服务端按照某个协议,向客户端返回Token
;客户端通过该协议,成功解析出服务端返回的Token
,然后在每次请求中携带该Token
。然后服务器端再根据协议,从中解析出Token
信息,获取请求用户信息。
当前常用的有Cookie
,Jwt
,OAuth2.0
等标准,其各有优缺点。其中Cookie
是一种存储在客户端浏览器中的数据。服务端可以通过设置HTTP响应头将Token
存储在Cookie
当中,并在后续请求中从Cookie
中读取Token
。而JWT
则是一种基于JSON格式的安全令牌,可用于在客户端和服务端之间传递信息。
之前,我们在 一文读懂Cookie 中,已经了解Cookie
的相关内容。基于此,我们这次使用Cookie
来实现上述所说的流程,按照Cookie
的规范来实现Token
的返回和请求中Token
的解析。
3. 实现
3.1 Cookie规范说明
这里我们对HTTP协议中的Cookie
规范再补充一下,这里分为两部分,第一部分是服务端如何向客户端发送 Cookie
,第二部分是客户端向服务端发送请求时如何携带Cookie
信息。
对于服务端向客户端发送Cookie
的手段,HTTP协议存在一个Set-Cookie
的头部字段,服务器可以通过Set-Cookie
头部字段将Cookie
发送给客户端。例如下面这个例子:
Set-Cookie: username=abc; expires=Wed, 09 Jun 2023 10:18:14 GMT; path=/
在这个例子中,服务器设置了一个名为username
的Cookie
,它的值是abc
,过期时间是2023年6月9日,路径为/
。浏览器在接收到该Cookie
时,便将其保存起来。
客户端请求时携带Cookie
的方式,则是通过HTTP协议中的Cookie
头部字段,客户端可以通过该头部字段携带信息给服务器端,比如下面这个例子:
Cookie: sessionid=1234
在这个例子中,HTTP请求中携带了一个name
为sessionid
,value
为 1234
的 Cookie
。当服务器端接收到该HTTP
请求后,从中解析出Cookie
的信息,然后基于此实现后续的流程。
3.2 实现说明
回看上述流程,主要分为两个大部分: 客户端和服务器端。在客户端部分,关键任务包括保存浏览器返回的Cookie
信息以及在请求时携带Cookie
信息给服务器。对于服务器端,则是在通过身份校验之后,能够按照规范客户端返回Cookie
,并在接收到请求时,能够正确解析出请求中的 Cookie
信息,识别出用户信息。
对于客户端部分,在浏览器接收到HTTP响应时,如果响应体中有Set-Cookie
头部字段,浏览器会自动保存Cookie
信息;客户端发起请求时,需要将 Cookie
信息传递给服务器。此时浏览器会自动携带通过校验的Cookie
。如果通过校验,此时会在HTTP请求头中携带Cookie
信息给服务端,下面是一个大概的校验流程:
在整个流程中,客户端保存Token
信息和在请求时携带Token
信息这两部分工作,浏览器已经帮我们实现了。剩下的工作集中在服务端的,主要涉及按照Cookie
的规范给客户端返回用户标识,并在接收到客户端请求时从HTTP请求中读取Cookie
以获取到用户的信息。与Cookie
相关的详细内容可以参考文章一文读懂Cookie。
因此下面我们需要做的两件事情,其一,服务器需要按照Cookie
的规范往客户端发送Cookie
的内容;其次,服务器在处理请求时,需要从HTTP请求头中读取出Cookie
的信息,成功识别用户身份。
Gin
框架中提供了一些API
,能够帮助我们在服务端,按照Cookie
规范给客户端发送Cookie
信息,同时也有API
能够帮助我们解析Cookie
的信息。下面我们先来了解相关的API
,然后再基于这些API
,搭建一个能够自动识别用户信息的 Web
应用程序。
3.3 API说明
3.3.1 SetCookie
gin.Context
对象中的 SetCookie
方法用于向客户端返回响应的同时,在Set-Cookie
头部携带Cookie
信息。下面是该方法的详细说明:
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
name
:cookie 的名称(必须)。value
:cookie 的值(必须)。maxAge
:cookie 的过期时间,以秒为单位。如果为负数,则表示会话 cookie(在浏览器关闭之后删除),如果为零,则表示立即删除 cookie(可选,默认值为-1)。path
:cookie 的路径。如果为空字符串,则使用当前请求的 URI 路径作为默认值(可选,默认值为空字符串)。domain
:cookie 的域名。如果为空字符串,则不设置域名(可选,默认值为空字符串)。secure
:指定是否仅通过 HTTPS 连接发送 cookie。如果为 true,则仅通过 HTTPS 连接发送 cookie;否则,使用 HTTP 或 HTTPS 连接都可以发送 cookie(可选,默认值为 false)。httpOnly
:指定 cookie 是否可通过 JavaScript 访问。如果为 true,则无法通过 JavaScript 访问 cookie;否则,可以通过 JavaScript 访问 cookie(可选,默认值为 true)。
在处理函数中,通过调用SetCookie
方法,便可以向客户端发送一个HTTP cookie。这里举一个代码示例,来帮助读者更好得理解该API
,下面举一个代码示例,如下:
func main() {
router := gin.Default()
router.GET("/set-cookie", func(c *gin.Context) {
c.SetCookie("user", "john", 3600, "/", "", false, true)
c.String(http.StatusOK, "cookie set successfully")
})
router.Run(":8080")
}
在这个示例中,使用 SetCookie
方法设置一个名为user
的 cookie。这个 cookie 的值是john
,在 1 小时后过期。该代码还设置了路径为“/”以及HttpOnly属性为true。
下面启动该服务器,客户端向服务端发送请求,请求路径为/set-cookie
,上面的处理函数将会被执行,然后我们来看其响应内容:
# 1. 发送请求
curl -i http://localhost:8080/set-cookie
# 2. 返回响应
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Set-Cookie: user=john; Path=/; Max-Age=3600; HttpOnly
Date: Sun, 20 Aug 2023 07:39:15 GMT
Content-Length: 23
cookie set successfully
查看上面第6行,可以看到,我们通过SetCookie
方法,成功设置了一个Cookie
,然后以在HTTP头部的形式返回。
3.1.2 Cookie方法
往客户端返回Cookie
后,浏览器会将Cookie
保存起来,然后在下次请求时将Cookie
跟随请求一起发送给服务器端。
在HTTP无状态协议的情况下,我们使用Cookie
来识别用户信息,此时服务器端需要正确解析出HTTP 头部中Cookie
的信息,Gin
框架中的gin.Context
提供了Cookie
方法,方便我们获取到Cookie
的信息。下面是该方法的定义说明:
func (c *Context) Cookie(name string) (string, error)
使用Cookie
方法可以获取指定名称的Cookie值,如果不存在指定名字的Cookie
,此时将会返回错误。下面给一个简单示例代码的说明:
func main() {
router := gin.Default()
// 定义路由
router.GET("/cookie", func(c *gin.Context) {
// 获取名为 "username" 的 cookie
cookie, err := c.Cookie("username")
if err != nil {
// 如果 cookie 不存在,则返回错误信息
c.JSON(http.StatusBadRequest, gin.H{"error": "Bad request"})
return
}
// 在响应中返回 cookie 值
c.JSON(http.StatusOK, gin.H{"username": cookie})
})
router.Run(":8080")
}
在上述示例中,我们定义了一个 /cookie
路由,使用 c.Cookie("username")
方法来获取名为 username
的 Cookie 值。如果 Cookie 不存在,则返回一个错误响应。否则,我们将在响应中返回 Cookie 的值。
下面我们通过curl
命令来对/cookie
请求,通过 -b
标识来携带cookie
值:
# -v, --verbose 这个参数会打开curl的详细模式,输出一些额外的信息,包括HTTP请求和响应头信息。
curl -b -v -b "username=hello cookie;" http://localhost:8080/cookie
下面我们来看具体的请求体和响应体的内容:
GET /cookie HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.79.1
Accept: */*
Cookie: username=hello cookie;
可以看到,我们请求体携带了Cookie
字段,Cookie
的名称为 username
,我们前面服务器端便是尝试获取名为 username
的 Cookie,下面我们看请求的响应体,看是否成功解析了HTTP 请求 Cookie的内容:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 20 Aug 2023 08:12:45 GMT
Content-Length: 27
{"username":"hello cookie"}
可以看到,服务端程序通过Cookie
方法成功解析了HTTP请求头部中Cookie
字段的值,然后将解析的结果正常返回客户端。
3.4 代码实现
下面我们来搭建一个基于Cookie
实现用户身份验证的Web
应用程序,首先需要一个登录页面,用于验证用户身份信息,验证通过后,我们将通过Cookie
给客户端返回一个 Token
。
同时,我们还需要创建一个页面,需要验证用户身份信息,在验证过程中,我们会检查用户请求中是否携带Cookie
,同时Cookie
中携带的数据是否正确,基于此实现用户身份的验证。下面是一个简单代码的示例:
func main() {
route := gin.Default()
route.GET("/login", func(c *gin.Context) {
// HTTP 响应中携带 Cookie
// Set cookie {"label": "ok" }, maxAge 30 seconds.
c.SetCookie("label", "ok", 30, "/", "localhost", false, true)
c.String(200, "Login success!")
})
route.GET("/home", func(c *gin.Context) {
// 获取 name = label 的 Cookie 的 value
if cookie, err := c.Cookie("label"); err == nil {
// 判断 Cookie的value 是否满足预期
if cookie == "ok" {
c.JSON(200, gin.H{"data": "Your home page"})
}
} else {
c.JSON(http.StatusForbidden, gin.H{"error": "Forbidden with no cookie"})
}
})
route.Run(":8080")
}
首先是一个/login
请求路由,通过SetCookie
方法给客户端返回Cookie
,基于此返回用户Token
。
然后/home
路由的处理,则是通过gin.Context
中Cookie
方法获取到HTTP请求头部中Cookie
的信息 ,然后验证Cookie
中的value是否满足预期。
这个是一个简单的代码示例,比如用户身份认证机制等,则需要自行完善,这里不再完整展示。
4. 原理
下面将简单描述gin.Context
对象中SetCookie
方法和Cookie
方法的实现原理,帮助读者更好使用这两个API
。
4.1 SetCookie方法
SetCookie
方法的实现原理如下,首先,SetCookie
方法会创建一个http.Cookie
对象,并设置其名称、值、路径、域名、过期时间等属性。例如,以下代码创建了一个名为sessionid
的Cookie
:
cookie := &http.Cookie{
Name: "sessionid",
Value: "1234",
Expires: time.Now().Add(24 * time.Hour),
Path: "/",
Domain: "",
Secure: false,
HttpOnly:true,
}
接下来,将上述Cookie
对象转换为字符串格式,并设置到HTTP响应头的Set-Cookie
字段中。代码实现如下:
func SetCookie(w ResponseWriter, cookie *Cookie) {
if v := cookie.String(); v != "" {
w.Header().Add("Set-Cookie", v)
}
}
这里第三行将Cookie
存储到Header
对象当中,Header
是专门用于存储HTTP响应头部的信息。调用Add
方法时,会根据指定的Key
,在 Header
对象中查找相应的值列表。如果这个键不存在,则会在 Header
对象中创建一个新的值列表;否则,会在已有的值列表末尾添加新的值,大概流程如下:
在返回HTTP响应时,会遍历Header
对象,填充HTTP响应头部信息,然后返回给客户端,比如上面Header
生成的HTTP响应头部如下:
Set-Cookie: v1
Set-Cookie: v2
Agent: Windows
SetCookie
方法便是通过上述所说流程,将Cookie
的信息设置到HTTP响应体头部当中去,然后返回给客户端。
4.2 Cookie方法
在调用 Cookie()
方法时,系统会首先检查请求头部中是否包含名为 Cookie
的字段。如果该字段不存在,则返回空字符串。
如果请求头部中包含 Cookie
字段,同时Cookie
的name
为调用Cookie()
方法指定的值,则系统会解析该字段并将其转换为一个 http.Cookie
对象。这个对象包含了所有的 Cookie
属性,例如名称、值、路径、过期时间、域名等等。最后,返回转换后的http.Cookie
对象中值,大概流程如下:
总的来说,Cookie()
方法的实现原理比较简单,它只是通过查找 HTTP 请求头部中的 Cookie 信息,并将其转换为 http.Cookie
对象来获取请求中特定 Cookie 值。
5. 总结
在本文中,我们深入探讨了Web应用程序在处理用户信息时所面临的挑战,特别是在HTTP协议作为无状态协议的背景下。我们从这一矛盾出发,介绍了解决方案中的Token
机制,并引出了基于Cookie
的实现方案。
我们详细阐述了Cookie
的规范,包括服务端如何发送Cookie
以及客户端如何在请求中携带Cookie
信息。
我们进一步深入探讨了具体的实现方式,并介绍了Gin
框架提供的API
,这些API
使得在服务端按照Cookie
规范发送和解析Cookie变得更加容易。通过一个实际的代码示例,我们演示了如何使用这些API来构建一个基于Cookie实现用户身份验证的Web应用程序。
在探讨API
的使用之余,我们也深入剖析了Gin框架提供的API的实现原理,为读者提供了更深层次的理解。
基于此,完成了对Gin中Cookie支持的介绍,希望对你有所帮助。
一文了解Gin对Cookie的支持的更多相关文章
- 一文彻底弄懂cookie、session、token
前言 作为一个JAVA开发,之前有好几次出去面试,面试官都问我,JAVAWeb掌握的怎么样,我当时就不知道怎么回答,Web,日常开发中用的是什么?今天我们来说说JAVAWeb最应该掌握的三个内容. 发 ...
- 1.部分(苹果)移动端的cookie不支持中文字符,2.从json字符串变为json对象时,只支持对象数组
1.移动端的cookie不支持中文字符.可以用编码,解码的方式解决. 2.json字符串变成相应 的,json对象数组字符串.就这样 3.不同客户端(移动端.电脑)的请求,在C#服务端的取时间的格式竟 ...
- cookie不支持中文,必须转码后存储,否则会乱码
cookie不支持中文,必须转码后存储,否则会乱码 Cookie ck = new Cookie("username", URLEncoder.encode(name, " ...
- 文档资源搜索小工具 - 支持PDF,DOC,PPT,XLS
最近做了一个文档搜索小工具,当然不是网盘搜索工具,这个工具支持四种文件格式搜索(pdf,doc,ppt,xls),你只需要在搜索框中输入你想要搜索资源的关键词,点击搜索按钮即可获取相关资源,点击下载按 ...
- MFC单文档程序添加HTML帮助支持
1.在App类 构造函数中添加 EnableHtmlHelp(); 2.在Frame类中,添加消息影射: ON_COMMAND(ID_HELP_FINDER, CFrameWnd::OnHelpFin ...
- 为WebClient增加Cookie的支持
我们经常会在应用程序中使用到WebClient模拟访问网站资源并且进行处理,如果多次访问之间我们希望为他们保存Cookie,换句话说,第一个请求产生的Cookie能自动带到第二个请求的话,可以通过自定 ...
- 【抱怨文】vscode对多项目支持不够友好
vscode是一个简单的开发工具,启动快,速度快.但是当前1.26版本对多项目支持好像有点问题.命令行有个dotnet sln,但是只能添加新项目,却没有创建解决方案的命令.如果强行添加他会提示没有解 ...
- 一文彻底搞懂Cookie、Session、Token到底是什么
> 笔者文笔功力尚浅,如有不妥,请慷慨指出,必定感激不尽 Cookie 洛:大爷,楼上322住的是马冬梅家吧? 大爷:马都什么? 夏洛:马冬梅. 大爷:什么都没啊? 夏洛:马冬梅啊. 大爷:马什 ...
- 【ASP.NET 进阶】仿百度文库文档在线预览(支持格式.pdf,.doc,docx,xls,xlsx,.ppt,pptx)
在[ASP.NET]PDF文件在线预览(类似百度文库)基础上进行了office文件到pdf文件的转换,然后在显示出来,效果如下: 问题说明: 1.请通过以下方式添加 Office COM 组件. 2. ...
- 检测浏览器是否支持cookie方法
cookie 摘自: http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html Cookie是什么? Cookie 是一小段文本信息 ...
随机推荐
- 2021-07-02:正则表达式匹配。给定一个字符串s和一个匹配串p。“.“匹配单个字符。“*“匹配左边元素的多个字符。判断p是否匹配s。比如s=“ab“,p=“a.“,返回true。比如s=“ab“
2021-07-02:正则表达式匹配.给定一个字符串s和一个匹配串p."."匹配单个字符.""匹配左边元素的多个字符.判断p是否匹配s.比如s="ab ...
- [学习笔记]解决因C#8.0的语言特性导致EFCore实体类型映射的错误
今天下午在排查一个EF问题时,遇到了个很隐蔽的坑,特此记录. 问题 使用ef执行Insert对象到某表时报错,此对象的Address为空: 不能将值 NULL 插入列 'Address',表 'dbo ...
- Java程序设计复习提纲(下:图形界面)
目录 上:Java程序设计复习提纲(上:入门语法) - 孤飞 - 博客园 (cnblogs.com) 基本语法与编译运行 数据类型和关键字 常用语法 数组与字符串 异常处理 中:Java程序设计复习提 ...
- Netty实战(一)
目录 第一章 Java网络编程 1.1 Java NIO 1.2 选择器 第二章 Netty是什么 2.1 Netty简介 2.2 Netty的特性 2.2.1 设计 2.2.2 易于使用 2.2.3 ...
- 统信UOS系统开发笔记(三):从Qt源码编译安装之编译安装Qt5.12.8
前言 上一篇,是使用Qt提供的安装包安装的,有些场景需要使用到自己编译的Qt,所以本篇如何在统信UOS系统上编译Qt5.12.8源码. 统信UOS系统版本 系统版本: Qt源码下载 ...
- Python生成指定大小的文件
转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/400bd75c.html 你好,我是测试蔡坨坨. 在日常测试工作中,我们经常需要对上传的文件大小进行测试,例如:一个文件上传 ...
- 行行AI人才直播第2期:八友科技创始人梁斌博士《大模型训练数据的一些事》
行行AI人才是顺顺智慧和博客园合作运营的AI行业人才全生命周期服务平台. 自从 OpenAI 发布 ChatGPT 4.0 之后,大模型热度一直不减,国内不管是大厂还是创业团队纷纷杀入大模型领域,大模 ...
- 【Linux内核】内核源码编译
Linux内核源码编译过程 总体流程: 下载Linux内核源码文件 安装所需工具 解压源码文件并配置 make编译源码 下载busybox 配置busybox并编译 1. Linux源码编译 http ...
- 前端热力图组件heatMapGD中国地图 中国热力地图 广东省热力地图 广东省地图 地市选择
快速实现前端中国热力地图 广东省热力地图 广东省地图, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12407 # china 广东省热力 ...
- Serverless试飞员的夙愿 | 带您扶摇直上,酣畅淋漓的云上作战
上期博文带您体验了外挂云函数Demo包,感受通过云函数使用云数据库快速突破"音障",进入"长机"云函数+"僚机"云数据库的Serverle ...