Cookie
我的完整代码
使用场景
Cookie 使基于无状态的HTTP协议记录稳定的状态信息
Cookie 主要用于以下三个方面MDN:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
总结一句话:保存用户信息,方便发送到服务器
限制
function setCookie(name, value) {
document.cookie = name + "=" + value
}
for (let i = 1; i <= 300; i++) {
setCookie(i + 'cookie', "value" + i);
}
console.log(document.cookie.split(" ").length)
编码格式
cookie的基本格式为key=value
,设置这些属性时,属性之间由一个分号
和一个空格
隔开。
为什么需要转码?
字符串中逗号、分号、空格
被当做了特殊符号(相当于代码中的保留字)
实测分号
必须转码,会带来一些列问题。逗号、空格
好像没啥影响😨。
(1)escape() 与 unescape()
被废弃,MDN已不推荐使用
(2)encodeURIComponent() 与 decodeURIComponent()
使用encodeURIComponent()对value进行转码
console.log(encodeURIComponent("yyy,y;=y y"));//yyy%2Cy%3B%3Dy%20y
console.log(escape("yyy,y;=y y"));//yyy%2Cy%3B%3Dy%20y
console.log(decodeURIComponent("yyy%2Cy%3B%3Dy%20y"));//yyy,y;=y y
console.log(unescape('yyy%2Cy%3B%3Dy%20y'));//yyy,y;=y y
属性总览
maxAge 和 expires
maxAge
标示在 Cookie 失效之前需要经过的时间。(主推)
expires
标示 Cookie 的最长有效时间。(兼容)
expires
和maxAge
决定了 Cookie 存活时间
注意
-
expires
和maxAge
的单位都是毫秒
-
设置时间都是 GMT 时间,不是当地时间
domain 和 path
Domain
标识指定了哪些主机可以接受 Cookie。
Path
标识指定了主机下的哪些路径可以接受 Cookie。
Domain
和 Path
组合决定了 Cookie 应该发送给哪些URL。
secure 和 httpOnly
标记为 Secure
的 Cookie 只通过被 HTTPS 协议加密过的请求发送给服务端
标记为 httpOnly
的 Cookie 不能被客户端 JavaScript 脚本调用
Secure
和HttpOnly
加强了 Cookie 的安全性
SameSite
SameSite
属性用来限制第三方 Cookie。
创建 Cookie
客户端
可以使用封装好的库(例如:js-cookie )。也可以自己手动实现一下代码改自js-cookie.js的使用
function setcookie(name, value, time, path, domain) {
let exp = new Date();
exp.setTime(exp.getTime() + time);
document.cookie = name + "=" + escape(value) + ";expires=" + exp.getUTCDate() + ";path=" + path + ";domain=" + domain;
}
setcookie("age", "18", 6400, '/', "ybf.com")
服务端
使用 Koa 设置 Cookie 。会在 Header 中添加 Set-Cookie
ctx.cookies.set('id', 'apply', {
httpOnly: false
})
ctx.cookies.set('name', 'xiaomin', {
httpOnly: true
})
使用 Cookie
客户端
Cookie 挂载在document.cookie
上,你可以在控制台打印下试试。( Cookie没有开启httpOnly,就能拿到id=value)
我现在有2个 Cookie,一个开启 httpOnly,另一个不开启。
![1](https://camo.githubusercontent.com/f89d8792f29c67c219c0e270c4e1e007c94ac2a4bb9ba44a94941a02de6d6667/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630323233323233312e706e67)
可以看到我们只能拿到没有开启 httpOnly 的 Cookie
![2](https://camo.githubusercontent.com/da399c62eb109b6289f92ddf173101adb9cafd0f6bec1164bc1e3465a7f8af9e/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630323233323235332e706e67)
服务端
你本地存在 Cookie 时,在服务端设置获得
浏览器自动帮我们添加上 Cookie 这个 Header
![4](https://camo.githubusercontent.com/6d63d55ff013ebad7598a415385a689bb372185d01d30e4b24246be42a302135/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630333030323932332e706e67)
我能不能通过 Set-Cookie 这个 header 拿到cookie ?
答案:不能。
👉引用来自你真的完全理解XMLHttpRequest吗?
W3C的 xhr 标准中做了限制,规定客户端无法获取 response 中的 Set-Cookie
、Set-Cookie2
这2个字段,无论是同域还是跨域请求。
修改 Cookie
客户端
和创建 Cookie 步骤一致,可以改变 value 和 maxAge / expires。
服务端
直接重新设置即可。可以改变 value,maxAge / expires,httpOnly,secure
删除 Cookie
客户端
expires 设置为过期即可
服务端
直接重新设置即可,maxAge 设置为-1,expires 设置为过期时间
修改和删除注意
需要保持 path 和 domain 一致。
如果改变 path。原 Cookie 修改失败,会创建一个新 Cookie。
对一个已经存在对 Cookie,你不可以设置成其他二级域名
实际测试
会话 Cookie
浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
不指定domain和path
默认为当前文档的主机(不包含子域名)。如果指定了Domain
,则一般包含子域名。
path默认为\
。
第一条为指定域名,第二条不指定域名
![6](https://camo.githubusercontent.com/f9c945e0dedde568665902421a14de4f15127535c9c562a65fb2d5140f8595db/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630333135333532342e706e67)
子域名测试
在二级域名 ybf.com
设置 Cookie,去子域名 test.ybf.com
获取 Cookie
- 指定域名的情况下
![11](https://camo.githubusercontent.com/72021a6ef12b18e4ab78798dfb018c3f49d56f5c85cd66fca96e06a077c7ef00/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630333231323534352e706e67)
- 不指定域名的情况下
子域名将无法获取父域名设置的cookie
![13](https://camo.githubusercontent.com/e2d93503c20031a432b6a910c460a15421cde294dc1640ed24bd1e19db5bd817/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630333231323535382e706e67)
开启 secure 和 httpOnly
👉这里需要你准备一份证书
![7](https://camo.githubusercontent.com/860dabe34f68123cf3c29badd5844b3816a2a78e99dab50c6adeb5284e472d6b/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630333136323933352e706e67)
客户端 js 能否设置第三方域名
先在 ybf.com
设置 Cookie。
; (function (name, value, time, path, domain) {
let exp = new Date();
exp.setTime(exp.getTime() + time);
document.cookie = name + "=" + value + ";expires=" + exp.toUTCString() + ";path=" + path + ";domain=" + domain;
})("ybf", "ybf", 86400000, '/', "ybf.com")
; (function (name, value, time, path, domain) {
let exp = new Date();
exp.setTime(exp.getTime() + time);
document.cookie = name + "=" + value + ";expires=" + exp.toUTCString() + ";path=" + path + ";domain=" + domain;
})("acc", "acc", 86400000, '/', "acc.com")
域名相同毫无疑问可以设置上,我们去 acc.com
看看是否设置上了😏。
![12](https://camo.githubusercontent.com/9f5df93216eb7f0e785d2e8bc0da6dc2a6da38cba581aadfbefa9ee45a95ac91/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630343232343930342e706e67)
答案:不可以。
一个服务端能否设置2个域名的 Cookie
ctx.Cookies.set('ybf', 'ybf', {
maxAge: 86400000,
domain: 'ybf.com',
httpOnly: false
})
ctx.Cookies.set('acc', 'acc', {
maxAge: 86400000,
domain: 'acc.com',
httpOnly: false
})
答案:不可以。
![15](https://camo.githubusercontent.com/2041250b5090c2bc53311ad9fd641ebd585939a716dfa81a3715c874560e9319/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630343232343932332e706e67)
你设置时会出警告,设置不上。This Set-Cookie was blocked because its Domain attribute was invalid with regards to the current host url。
在 3 级域名设置 2 级域名
我们执行以下代码,在test.ybf.com
设置ybf.com
。
; (function (name, value, time, path, domain) {
let exp = new Date();
exp.setTime(exp.getTime() + time);
document.Cookie = name + "=" + value + ";expires=" + exp.toUTCString() + ";path=" + path + ";domain=" + domain;
})("ybf", "ybf", 86400000, '/', "ybf.com")
![18](https://camo.githubusercontent.com/b1bbe99df6ab0b67da362f35538242194c65fadc08919d3de34dd149c877697a/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630353030303335392e706e67)
答案:可以。而且设置完 test.ybf.com
可以直接收到 Cookie。
在 2 级域名设置 3 级域名
我们执行以下代码,在 ybf.com
设置 test.ybf.com
; (function (name, value, time, path, domain) {
let exp = new Date();
exp.setTime(exp.getTime() + time);
document.cookie = name + "=" + value + ";expires=" + exp.toUTCString() + ";path=" + path + ";domain=" + domain;
})("ybf", "ybf", 86400000, '/', "test.ybf.com")
![20](https://camo.githubusercontent.com/1142130004ca67abbc82f8338abe5fec519d73669e52b6207091e0704e3dbd82/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f5942464143432f696d6765436c6f7564406d61737465722f696d672f32303230303630353030303930372e706e67)
答案:不可以
测试平台
这里需要你频繁的改host文件,推荐使用SwitchHosts!
我使用的使用浏览器版本
-
Chrome 版本 83.0.4103.61
-
Safair 版本13.1.1
-
Edge 版本 81.0.416.72
-
Firefox 77.0
参考
MDN
Set-Cookie
聊一聊 cookie
js-cookie.js的使用
COOKIE长度限制总结
Cookie 的 SameSite 属性