在前端的知识领域,cookie 是个很基础的东西,但真正对 cookie 有全面了解的恐怕不多。现在让我们一起劣实基础,更加全面了解其吧。
cookie的诞生
我们知道 http 是无状态的,这是指对于同一请求,只要请求参数相同,http 无法知道是哪个客户端发出的请求,也无法判断是否为已登录用户请求,这就导致了 http 无法记住用户的登录状态。所以 cookie 设计的初衷就是为了弥补 http 的无状态,帮助记录客户端的用户状态,作为用户登录凭证的载体。
通过服务器为登录用户设置 cookie 来保存当前的用户状态,每次请求时浏览器自动携带该域名下的 cookie 来告诉服务器当前请求的用户ID,与服务器的用户 sessionID 相匹配,从而确定当前用户及登录状态。
cookie的相关操作
设置cookie
通过JS设置
// 一次只能设置一对键值,但不像传统的JS一般,不会覆盖
document.cookie = 'name=xxx;';
服务端设置(node)
res.setHeader('Set-Cookie', 'name=xxx;');
修改cookie
修改 cookie 直接覆盖就行
document.cookie = 'name=xxx;';
删除cookie
设置过期时间为过去时间
document.cookie = 'name=xxx;expires=' + new Date('1999');
cookie 相关属性
expires
其值为时间字符串,用于设置过期时间,可设置过去时间才删除 cookie
document.cookie = 'name=xxx;expires=' + new Date('1999');
domain
domain 设置哪些网站可以接受 cookie,默认为 origin(其中 domain 须为当前请求(网页)域名或者主域,否则无效)
document.cookie = 'name=xxx;domain=a.xxx.com';
path
path 标识指定了主机下的哪些路径可以接受 cookie,默认为 /,其中 path 须存在于当前请求(网页)路径中
document.cookie = 'name=xxx;path=/xxx;';
Secure
标记为 Secure 的 cookie 限制只能在 https 中设置与传输。
// 如果在 http 下的网页中设置则不生效
document.cookie = 'name=xxx;Secure';
HttpOnly
设置 cookie 只能被请求携带,不能被 JS 访问,可以减少 xss 攻击,该属性只能在服务的设置。
res.setHeader('Set-Cookie', 'name=xxx;HttpOnly;');
SameSite
SameSite 可以设置为以下几个值
- none (旧 chrome 版本(80以下)默认规则)
浏览器会在同站请求、跨站请求下继续发送 cookies,不区分大小写
- Strict
浏览器将只在访问相同站点时发送 cookie。
- Lax (新 chrome 版本默认规则)
规则稍稍放宽,大多数情况也是不发送第三方 cookie,但是导航到目标网址的 get 请求除外。
导航到目标网址的 get 请求,只包括三种情况:链接,预加载请求,get 表单。详见下表。
请求类型 | 示例 | 正常情况 | Lax |
---|---|---|---|
链接 | <a href="..."></a> | 发送 Cookie | 发送 Cookie |
预加载 | <link rel="prerender" href="..."/ > | 发送 Cookie 发送 | Cookie |
GET 表单 | <form method="GET" action="..."> | 发送 Cookie 发送 | Cookie |
POST 表单 | <form method="POST" action="..."> | 发送 Cookie | 不发送 |
iframe | <iframe src="..."></iframe> | 发送 Cookie | 不发送 |
AJAX | $.get("...") | 发送 Cookie | 不发送 |
Image | <img src="..."> | 发送 Cookie | 不发送 |
设置为 Lax 和 Strict 可以杜绝很多 csrf 攻击
cookie 相关知识概念
请求自动携带
在浏览器中(老版本),请求(包括 get 和 post)会自动携带请求地址(服务器所在域名,注意不是发起请求所在的网页域名)的 cookie,跨域的 ajax 需要配置 withCredentials
。而在新版本浏览器上(chrome 80以上),因为 SameSite 的默认值为 Lax,所以跨域请求携带 cookie 被限制了,将不再可以携带配置为 Lax 的跨域 cookie。
生命周期
cookie 的生命周期默认为 session,即浏览器关闭后删除。如果设置了 expires,则由 expires 控制,如果浏览器关闭还没到过期时间,则会保存在硬盘中。
cookie 与 session 的区别
session 是服务端的一种机制,使用类似散列表的数据结构来保存用于用户信息,如登录状态。
cookie 则可以用于服务端保存登录状态,比如为客户端设置 cookie 来保存 session 对应的 sessionID,下次请求时客户端自动携带 cookie,服务的从中取出 sessionID,在从 session 表中获取用户登录状态及用户信息。
cookie 和 token 的关系
token 是另一种流行的处理 http 无状态的方式,一般设置在请求头中。当用户登录成功时返回 token 给客户端,客户端再次请求时携带 token,服务端获取 token 后,再从 session 中获取用户信息及登录状态。
与 cookie 相比,因为 token 在代码中设置,不会在访问第三方网站时携带 cookie,可以有效避免 csrf 攻击。
cookie缺点
-
cookie 的大小一般被浏览器限制为
4kb
-
请求自动携带 cookie 其实会造成无效的带宽浪费
-
安全问题(csrf 与 xss)
总结
cookie 曾经是被各个网站使用的流行机制,但是随着 token 机制的运用及 html5 存储的兴起,其实已经有很多网站不再使用 cookie。但不管怎样,cookie 还是有很多独特运用场景的,作为前端还是有必要去学习及了解的。如果本文有错误的地方,欢迎大家纠正。
参考
欢迎来前端学习打卡群一起学习~516913974