写在前面
最近在开发过程中,遇到一些关于cookie的坑,趁此机会对cookie进行梳理一遍,加强记忆,有错误之处,还希望各位大佬予以纠正。
cookie是什么
无论是在面试过程中,还是在开发过程中,我们总是会被问到:cookie是什么?
我的理解是:
- cookie是一种传递数据的技术,通过cookie可以将一些数据从前端传递到后端,后端API接口可以通过
req.cookies属性来获取。 - cookie是浏览器管理状态的文件,我们可以通过JS代码读写该文件中的内容,达到管理状态的目的。
知道了cookie是什么,那么为什么要使用cookie呢?这是因为http是一个不保存状态的协议,即服务器在处理请求的时候,并不清楚这些请求是否来自同一个浏览器,相关的逻辑不好处理。
于是开发人员就想着:如果我在给服务器发送请求的时候,能传递一些表示状态的值,就可以让服务器知道这些请求来自一个浏览器,那么问题不就解决了吗?于是便产生了cookie这一技术。
cookie的属性
cookie的常见属性有以下五种,这里对其做简单介绍
-
name: cookie的名字,一个域名下的cookie名字不能重复,否则会被覆盖。
-
value: cookie的值
-
domain: cookie绑定的域名,如果没有设置,就会自动绑定到执行语句所在的域名。值得注意的是:,统一个域名下的二级域名也是不可以交换使用cookie的,比如,你设置www.baidu.com和image.baidu.com,依旧是不能公用的。
-
path: cookie所采的目录,默认值是/(即根目录)。cookie目录有管理cookie访问权限的作用,比如:将cookie1的path设置为/root/,将cookie2的path设置为/root/book。
那么/root/下的所有页面都有权限访问cookie1,/root/keys/、/root/phones/下的页面没有权限访问cookie2,只有/root/book/下的页面才有权限访问cookie2。
-
Expires: cookie的过期时间,后文会进行详细介绍。
-
Security: Cookie的Secure属性,意味着保持Cookie通信只限于加密传输,指示浏览器仅仅在通过安全/加密连接才能使用该Cookie。如果一个Web服务器从一个非安全连接里设置了一个带有secure属性的Cookie,当Cookie被发送到客户端时,它仍然能通过中间人攻击来拦截。
-
HttpOnly: Cookie的HttpOnly属性,指示浏览器不要在除HTTP和HTTPS请求之外暴露Cookie。
一个有HttpOnly属性的Cookie,不能通过非HTTP方式来访问,例如通过调用JavaScript(例如,引用 document.cookie)。
因此,不可能通过跨域脚本(一种非常普通的攻击技术)来偷走这种Cookie。尤其是Facebook 和 Google 正在广泛地使用HttpOnly属性。
如何设置cookie
1. 如何在前端设置cookie
// 设置最简单的cookie,其他属性为默认
document.cookie = "hobby=book;"
// 设置cookie的过期时间为2个小时之后
let expiresDate = new Date();
expiresDate.setTime(expiresDate.getTime() + (1000 * 60 * 60 * 2))
document.cookie = `hobby1=book; expires=${expiresDate.toGMTString()}`;
2. 如何在前端读取cookie
可以直接通过 document.cookie 来获取包含所有cookie字符串,比如:"name=Allen; height=175; gender=male"。也可以通过类似以下函数处理cookie,返回一个对象:
function getCookieObj() {
let cookieArray = document.cookie.trim().split(";");
let equalIndex = 0;
let cookieObj = {};
cookieArray.forEach(cookie => {
if (cookie.trim().split("=").shift()) {
equalIndex = cookie.trim().indexOf("=");
cookieObj[cookie.trim().split("=").shift()] = cookie.trim().substring(equalIndex + 1);
}
});
return cookieObj;
}
console.log(getCookieObj());
/*
{
gender: "male",
height: "175",
name: "Allen"
}
*/
3. 如何在后端设置cookie
无论你的项目后端使用的是什么语言,只要相关API返回的HTTP响应头中包含如下信息,就认为后端要求设置一个cookie,前端接收到这个响应之后,就会在浏览器中保存这个cookie:
Set-cookie: name=name; expires=date; path=path; domain=domain
以Node.js为例,我们可以使用如下代码进行设置cookie:
// 设置基础的cookie
res.writeHead(200, {
'Set-Cookie': 'myCookie=test',
'Content-Type': 'text/plain'
});
// 设置多个cookie
res.writeHead(200, {
'Set-Cookie': ["aaa=bbb","ccc=ddd","eee=fff"],
'Content-Type': 'text/plain'
});
// 设置包含多个属性的cookie
res.writeHead(200, {
'Set-Cookie': 'myCookie=test; Expires=Wed, 13-Jan-2021 22:23:01 GMT;HttpOnly ',
'Content-Type': 'text/html'
});
这是使用原声Node.js进行设置cookie,如果你们项目中使用了Express.js框架,那么设置cookie将会更方便:
// 可以直接使用Express.js提供的api进行设置cookie
function(req, res, next){
...
res.cookie(name, value [, options]);
res.cookie('user',1,{ expires: new Date(Date.now() + 100), httpOnly: true });
...
}
4. 如何在后端读取cookie
当前端往后端发送请求的时候,cookie会被自动放置在HTTP请求头中,所以我们在后端可以直接在请求中进行获取,下面还是以Node.js为例:
http.createServer(function (req, res) {
...
console.log(req.headers.cookie); // 获得客户端的Cookie
...
}).listen(8000);
相应的,如果你使用了Express.js框架,那么获取cookie将会更加方便:
var express=require('express');
var cookie=require('cookie-parser');
var app=express();
app.use(cookie()); // 使用cookie-parser中间件
app.get('/',function(req,res){
...
console.log(req.cookies); // req.cookies是一个cookie对象,可以直接通过键值对的形式获取cookie
...
});
自己使用cookie的经验
结合自己的开发经历,这里总结出一些自己的经验:
- 不要将一些敏感信息放在cookie里面,例如记录用户信息的jwt
- 尽量减少在前端设置cookie,尽可能通过后端API记性设置,并且将Secure和HttPOnly属性设置为true,这样可以防止XSS攻击。
- 对于一些需要保存在cookie里面的数据,注意设置cookie的过期时间。