Cookie概述
客户端存储应使用Storage和IndexedDB,只有每次请求都需要传递给服务器的信息才应放入Cookie
主要用途
- 会话管理(保存会话状态信息):登录信息、购物车记录等
- 个性信息(保存用户个性化信息):用户偏好、页面字体大小、页面背景色等
- 追踪用户(保存用户使用信息):记录和分析用户行为等
组成部分
- Cookie名称
- Cookie的值:存储真正的数据
- 过期时间:超过次时间Cookie失效
- 所属域名:默认为当前域名
- 生效路径:默认为当前网址,cookie仅在访问生效路径及其子路径时生效
存储限制
- 存储空间:一般单个域名设置的Cookie不应超过30个,且每个大小不应超过4KB(超出会被忽略)
- 存储时长:在设置的Cookie过期时间之前数据一直有效,即使窗口或浏览器关闭也不会被清除
- 同源限制:Cookie受同源政策限制(实际中协议不同,仅主机与端口号相同的两个网址也可共享Cookie)
Cookie缺点总结:存储容量小,缺乏数据操作接口,且影响性能
Cookie原理
Cookie由HTTP协议生成,主要供HTTP协议使用,是服务器保存在浏览器的一小段文本信息,浏览器每次向服务器发出请求时会自动携带这段信息
生成Cookie(服务器)
- Cookie由服务器端生成,保存于HTTP响应头中
- 后端在HTTP响应头中添加一个或多个
Set-Cookie
字段(每个均可附带Cookie属性) - 注意:服务器收到浏览器发来的Cookie时有2点无法区分(Cookie的各种属性、Cookie是由哪个域名设置的)
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: <cookie-name1>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name2>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
发送Cookie(客户端)
- Cookie在浏览器发送HTTP请求时自动携带
- 发送HTTP请求时会自动匹配并携带与目标服务器URL的Domain和Path向匹配的Cookie
- 前端在HTTP请求头中添加一个
Cookie
字段(该字段可包含多个Cookie,使用分号分隔) - 注意:路径匹配越精准的Cookie排在越前面,不同路径下的同名Cookie不会覆盖(若为父子关系会一起携带)
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: <cookie-name1>=<cookie-value>; <cookie-name2>=<cookie-value>
Cookie格式
Cookie字段
- Cookie字段必须以
key=value
格式写入(注意:等号两侧不能有空格) - Cookie字段的key与value中包含分号、逗号和空格时必须转义(推荐:encodeURIComponent方法)
- Cookie字段与Cookie属性间使用
;
分隔(说明:Cookie属性无先后顺序,详细见下文)
Cookie属性
-
Expires
:指定到期时间(值为UTC格式的时间字符串),未指定或指定为null时,若amx-age也未指定,则过期时间同sessionStorage -
Max-Age
:指定有效时长(值为从现在开始存在的秒数),与expires同时指定时优先生效 -
Domain
:指定所属域名(默认值为当前一级域名),未指定时不携带子域名的Cookie,手动指定时自动携带指定域名及其子域名的Cookie,指定的域名必须为当前域名的一部分(否则出现跨域问题浏览器拒收该Cookie) -
Path
:指定生效路径(值为绝对路径,默认为当前路径),自动携带生效路径及其子路径的Cookie -
Secure
:指定开启安全上下文(无属性值),开启后仅在安全协议下发送含Secure的Cookie,其他协议忽略 -
HTTPOnly
:指定拒绝脚本获取(无属性值),开启后仅浏览器发送请求时自动携带Cookie,脚本接口获取不到 -
SameSite
:限制第三方Cookie,防止CSRF攻击和用户追踪,用于存储用户的身份信息- 属性值为
Strict
:完全限制第三方Cookie,影响用户体验(跳转的页面都是未登录状态) - 属性值为
Lax
:限制大部分第三方Cookie,超链接、预加载请求和get表单请求除外(浏览器默认) - 属性值为
None
:关闭SameSite属性(注意:关闭生效的前提是必须同时设置Secure属性,否则无效)
- 属性值为
Set-Cookie: k1=v1; expires=Thu, 01-Jan-2070 00:00:01 GMT; // 指定Expires
Set-Cookie: k1=v1; max-age=360 // 指定Max-Age
Set-Cookie: k1=v1; domain=example.com // 指定Domain
Set-Cookie: k1=v1; Path=/ // 指定Path
Set-Cookie: k1=v1; Secure // 指定Secure
Set-Cookie: k1=v1; HTTPOnly // 指定HTTPOnly
Set-Cookie: k1=v1; SameSite=Strict // 指定SameSite为Strict
Set-Cookie: k1=v1; SameSite=Lax // 指定SameSite为Lax
Set-Cookie: k1=v1; SameSite=None; Secure // 指定SameSite为None
Cookie操作
读取Cookie
📄基于HTTP协议的Cookie通信格式,一次可读出全部Cookie(前提:该Cookie未指定HTTPOnly
属性)
document.cookie // 返回Cookie字符串,多个Cookie间以分号分隔,如"user=admin;pwd=123456"
新增Cookie
📄基于HTTP协议的Cookie通信格式,一次只能写入一个Cookie(写入方式为追加写入,而不是覆盖)
document.cookie = "user=admin" // 新增cookie
document.cookie = "pwd=123456" // 新增cookie
document.cookie // "user=admin;pwd=123456"
修改Cookie
📄修改Cookie必须同时满足四个条件(即key
、domain
、path
、secure
都匹配),否则均为新增Cookie
document.cookie = "k1=v1;domain=example.com;path=/index" // 旧Cookie
document.cookie = "k1=v2;domain=example.com;path=/index" // 修改成功
document.cookie = "k1=v3;domain=example.com;path=/" // 修改失败
document.cookie // "k1=v2;k1=v3"
Set-Cookie: k1=val1; domain=example.com; path=/blog // 旧Cookie
Set-Cookie: k1=val2; domain=example.com; path=/blog // 修改成功(值更新为val2)
Set-Cookie: k1=val3; domain=example.com; path=/ // 修改失败(创建一个同名的新cookie)
删除Cookie
📄删除一个现存Cookie的唯一方法就是将它的expires
属性设置为一个过去的日期(过期Cookie会被自动清除)
document.cookie = 'user=admin;expires=Thu, 01-Jan-2070 00:00:01 GMT'; // 旧Cookie
document.cookie = 'user=;expires=Thu, 01-Jan-1970 00:00:01 GMT'; // 删除成功
document.cookie // ""
参考链接
- MDN Web Docs,官方参考
- Scotthelme,Cookie安全性参考
- Netsparker,Cookie的安全性参考
- Web Dev,第一方和第三方Cookie参考以及网络原理
- BookStack,JavaScript Cookie参考