一、简介
Cookie
(也称为 HTTP Cookie
、Web Cookie
、浏览器 Cookie
等等)是服务器发送到用户浏览器并保存在本地的一小块数据,该数据通常是用户账号相关的信息,不同浏览器对 Cookie
的数量和大小限制不同,但一般来说,单域名下设置的 cookie
不能超过 30 个,单条 cookie
的大小不能超过 4kb。如果 Cookie
超出浏览器限制,则会被浏览器忽略,不被保存。而且 Cookie
可以设置过期时间,到达过期时间后,浏览器就会把 Cookie
清除掉。
设置Cookie 的方式有两种:服务端通过在 HTTP 响应头中的 Set-Cookie
字段设置,以及在前端通过 JS 的 document.cookie
设置。在浏览器在拥有 Cookie 之后,每次向服务器发送请求时,都会自动携带对应地址的 Cookie。但是用户可以手动操作浏览器接受、拒绝和删除 Cookie,以及是否向服务器发送 Cookie。
Cookie有两种类型:会话期Cookie
和 持久性Cookie
。会话期Cookie
不设置具体失效时间,只会在当前会话结束之后,被删除掉。被存储在内存中,当会话关闭时,该 Cookie
永久丢失。重新发起会话时,会创建一个新的 会话期Cookie
。持久性Cookie
会设置好具体的有效期,被存储在磁盘中,浏览器关闭不会影响该 Cookie
,只有当有效期结束时,才会从磁盘中将该 Cookie
删除。在有效期内,会一直复用该 Cookie
。
Cookie 可以解决 HTTP 无状态引发生的问题。HTTP 无状态是指 HTTP 协议属于一种无状态协议,表示服务端不会在两个请求之间,保留任何状态(数据),请求之间没有关联,相对独立。如果后续请求需要用到前面请求中的相关状态,那就得进行重传,导致后续请求传送的数据量增大。而借助 Cookie 就可以帮助 HTTP 记录稳定的状态信息,减少数据的重传。
二、属性
cookie 共拥有以下 13 条属性,前 10 条被广泛支持,后 3 条目前仅在 chrome 浏览器中能看到:
1、Name
cookie
的名字,是唯一代表该 cookie
的 key
,不可包含 空格
、制表符
、控制字符
、()
、<>
、,
、;
、:
、"
、/
、[]
、{}
等多种特殊字符。
2、Value
cookie
的 value
值,代表要存储的数据,同样不可包含 空格
、制表符
、控制字符
、()
、<>
、,
、;
、:
、"
、/
、[]
、{}
等多种特殊字符。与 cookie
的 name
属性以 =
号连接。
// 设置cookie
'cookie1=cookie1'
3、Domain
设置 cookie
作用的域名,属性值为字符串,表示哪些域名及其子域名可以访问到该 cookie
(不区分协议和端口号,只针对域名),也就是哪些域名下的请求可以携带该 cookie 。默认为设置 cookie
时的当前域名,不包含其子域名。
注意: 如果设置 Domain
的域名前面加 .
,则表示包含该域名的子域名,否则仅作用于该域名。在部分浏览器中只要设置了 cookie
的 Domain
属性,则浏览器在存储 cookie
时,会自动给域名前面加 .
,使得子域名也能访问该 cookie
;相反,如果没有设置 cookie
的 Domain
属性,从而采取默认设置,则浏览器不会自动给域名前面加 .
,子域名也就无法访问该 cookie
。(有待验证!!!)
// 设置cookie作用的域名为 .a.com
'cookie1=cookie1;Domain=.a.com;'
// 则a.com 和 b.a.com 都能访问该cookie
4、Path
设置 cookie
作用的 URL 路径,属性值为 /
开头的字符串,该路径是基于 Domain
设置的域名基础上的路径,进一步限定 cookie 的作用域,表示只有匹配该路径下的请求才会携带这个 cookie,该路径下的子路径也属于匹配。但是该路径的上级路径的请求,是属于不匹配的情况所以不会携带这个 cookie 的。路径开头的 /
可以理解为文件目录分隔符,所以此目录的下级目录也都可以匹配,都能携带这个cookie。
// 设置cookie的path为 /c
'cookie1=cookie1;Domain=.a.com;path=/c'
// 则 https://www.a.com/c、https://www.a.com/c/c1、https://www.a.com/c/c1/c11等
// 都可以携带该cookie
// 如果设置cookie的path为 /c/c1
'cookie1=cookie1;Domain=.a.com;path=/c/c1'
// 则 https://www.a.com/c/c1、https://www.a.com/c/c1/c11等路径可以携带该cookie
// 但是https://www.a.com/c 不会携带该cookie
5、Expires
设置 cookie
的有效期,属性值为符合 HTTP-Date 规范(例如:Wed, 21 Oct 2023 07:28:00 GMT)的时间戳数据,到达该有效期时间后,cookie
会失效被删除掉。我们可以通过设置 cookie
的 Expires
属性为一个已经过去的时间,从而使 cookie
失效。
注意: 该有效期时间是以客户端的时间为准。
// 设置Cookie的有效期 到达该时间后Cookie过期
'cookie1=cookie1;Expires=Wed, 21 Oct 2023 07:28:00 GMT;'
// 获取某个时间点的UTC时区的时间戳数据
let date = new Date('2023-2-28 1:30:00').toUTCString()`
6、Max-Age
设置 cookie
多长时间后失效,属性值为 Number
数据,单位为秒。如果属性值为 正数 ,表示该 cookie
会在正数秒后失效,然后被浏览器清除掉。如果属性值为**0
,则表示该 cookie
立即失效,被浏览器清除掉。如果属性值为 负数**,则表示该 cookie
是一个临时 cookie
,存储在浏览器内存中,仅在当前浏览器窗口以及本窗口打开的相关子窗口有效,当窗口关闭后,该 cookie
就会失效,然后被浏览器清除掉。
注意: 如果 Expires
属性与 Max-Age
属性,同时被设置,则 Max-Age
属性的优先级高,Expires
属性将不起作用。如果 Expires
属性与 Max-Age
属性都没有设置,则为会话期 cookie
,关闭浏览器后失效。
`// 设置Cookie的有效期 10秒后Cookie失效
'cookie1=cookie1;Max-Age=10;'
// 同时设置Expires和Max-Age时,Max-Age优先级高 10秒后cookie失效
'cookie1=cookie1;Expires=Wed, 21 Oct 2023 07:28:00 GMT;Max-Age=10'
// 使cookie立即失效
'cookie1=cookie1;Max-Age=0;'`
7、Size
表示 cookie
存储的数据大小,单位是字节,一般 单条 cookie
的总大小不能超过 4kb,也就是 4096 字节。
注意: 4kb 是单条 cookie 的大小限制,而不是所有 cookie 的总大小限制。
浏览器 | cookie 数量限制 | cookie 大小限制/单位:字节 |
---|---|---|
Chrome | 150 | 4096 |
IE | 50 | 4095 |
FireFox | 50 | 4097 |
Opera | 30 | 4096 |
Safari | 无限 | 4097 |
8、HttpOnly
设置 cookie
是否可以被前端通过 JS
的 document.cookie
访问到,如果设置为 true
,则不能被 JS
操作,只能被浏览器和服务端操作,在请求中会被正常携带,反之,则可以被 JS
操作。通常设置该属性的 cookie
,都用于存储一些用户身份或者安全凭证之类的信息,可以防范 XSS攻击(跨站脚本攻击)。
9、Secure
设置 cookie
是否仅在使用 HTTPS
协议(localhost
除外)的请求中使用,设置该属性后的cookie,不会被使用 http
协议的请求携带。
10、SameSite
设置 cookie
是否可以随着跨站请求一起发送,即限制第三方 cookie
,属性值有三种:
① Strict
最严格的设置,在跨站时,完全禁止第三方 cookie
,只有在设置当前 cookie
的站的请求中(同站),才会携带这个 cookie
。也就是只有在网页的 URL
与请求的路径一致时,才会携带当前 cookie
。
注意: 在域名相同,但协议不同(HTTP
和 HTTPS
)时,浏览器也会将其视为不同站点。
② lax
默认设置,在跨站时,不会携带第三方 cookie
,但是在导航到源站点的 get
请求中,当前 cookie
会被携带。导航到源站的情况总共有下面三种:
请求类型 | 示例 | cookie 携带情况 |
---|---|---|
<a> 链接 | <a href="…"></a> | 携带 cookie |
预加载 | <link rel="prerender" href="…"/> | 携带 cookie |
GET表单 | <form method="GET" action="…"> | 携带 cookie |
③ none
最宽松的设置,无论是同站请求还是跨站请求,都会携带当前 cookie
。但是要注意设置该属性值时,必须同时设置 Secure
属性,保证安全的上下文环境,否则将不生效。
在设置了 SameSite
属性值为 Strict
或 Lax
之后,就能很好的防范 CSRF
攻击(跨站请求伪造攻击)了。
11、SameParty
为了实现 First-Party Sets
策略所设定,但还未被广泛支持。后续补充。。。
12、Partiton Key
未知,后续补充。。。
13、Priority
chrome的提案,未被广泛支持,用来设置cookie的优先级,从低到高:Low
/ Medium
/ High
,当 cookie 数量超出时,低优先级的 cookie 会被优先清除。
三、操作
1、创建
① 服务端 Set-Cookie
服务端可以使用 Set-Cookie
响应头部向浏览器发送要设置的 cookie
信息,形式为键值对。浏览器在响应头中识别到“Set-Cookie 之后,会根据其内容创建对应的 cookie
。然后会在后续的请求中将创建的 cookie
发送回服务器。
如果想要同时设置多个cookie,则需要在响应头中包含多个 Set-Cookie
,一个 Set-Cookie
只能设置一个 cookie
。
Set-Cookie: cookie1=value1
Set-Cookie: cookie2=value2; Expires=Wed, 21 Oct 2023 07:28:00 GMT;
Set-Cookie: cookie3=value3; Max-Age=600
Set-Cookie: cookie4=value4; Domain=.a.com;Path=/b
Set-Cookie: cookie5=value5; HttpOnly
Set-Cookie: cookie6=value6; SameSite=None; Secure
② 前端JS的 document.cookie
前端可以通过JS的 document.cookie
获取或设置与当前页面相关的 cookie
信息,形式为键值对。
同样,这种方法一次只能设置一个cookie,如果想设置多个cookie,则需要多次使用 document.cookie
。
document.cookie = "cookie1=value1"
document.cookie = "cookie2=value2;Expires=Wed, 21 Oct 2023 07:28:00 GMT;"
document.cookie = "cookie3=value3;Domain=.test.com;Path=/b"
document.cookie = "cookie4=value4;SameSite=None; Secure"
③ 用户可以在浏览器开发者工具中的 Application 中直接创建 cookie
2、修改
在 Domain
和 Path
相同的情况下,前端可以通过重新给 cookie
赋值的方式来修改 cookie
,新设置的内容将会覆盖掉旧的内容。但如果 Domain
和 Path
发生了变化,那么将会生成一个新的 cookie
,与原来的 cookie
并存,虽然他们 name
相同,但却属于不同的 cookie
。
// 创建cookie
document.cookie = "cookie1=value1"
// 修改cookie的值
document.cookie = "cookie1=value1111"
// 修改cookie的值并修改path 相当于另外创建一个cookie
document.cookie = "cookie1=value123;path=/b"
除了 path
不同,其他属性都相同的两个 cookie
,是两个独立的 cookie
:
当然用户也可以在浏览器开发者工具中的Application中直接修改 cookie
的内容和属性。
3、删除
目前前端并不存在直接删除 cookie
的方法,我们只能通过设置 cookie
的 Expires
属性为一个已经过去的时间或者设置 Max-Age
属性设置为 0
,从而使 cookie
失效,然后被浏览器给清除掉。
// 删除cookie3 最好指明path 避免删错cookie
document.cookie = "cookie1=;path=/;max-age=0"
// 或
document.cookie = "cookie1=;path=/;expires=Thu, 01 Jan 1970 00:00:00 UTC;"`
当然用户也可以在浏览器开发者工具中的Application中直接删除 cookie
。
4、查询
前端可以通过 documen.cookie
获取到当前网页所有相关的 cookie
的 name
和 value
,以 name=value
的形式:
const allCookies = documen.cookie;
console.log(allCookies)
当然用户也可以在浏览器开发者工具中的Application中查看所有 cookie
。