其实,在平时的项目当中,早就遇到过很多关于Cookie的疑惑,那就开始系统性的学习一下吧。
Cookie是什么?
简单来说,HTTP是一个无状态协议,有了Cookie HTTP请求可以携带少量状态。
HTTP协议是一个无状态协议,即它不会对发送的请求和响应状态进行保存,上一次请求和下一次请求是不是来自于同一个用户,它根本无法识别。但是,在项目当中,我们希望浏览器能够保持登录状态、记住购物车中的物品和数量等等,这就需要用到Cookie。
cookie就是一个浏览器管理状态的一个文件。浏览器会存储set-cookie字段里面的信息,并在该请求之后的所有请求,都携带cookie在其请求头中发送给服务器,服务器就可以读取到信息达到保持用户状态的作用。
Cookie原理
在看这张图的时候,一直有几个疑惑:
- 我在项目当中如何区分第一次请求?
- 为什么没有看到返回set-cookie的请求?
我们以登录状态为例,第一次请求其实对应的就是每一次的用户登录(login),我们打开登录的接口,可以看到,用户将自己的用户名、密码以请求参数的形式发送给服务端。登陆成功之后会在响应头中发现set-cookie这个字段,意为服务器将用户的登录态加密之后返回给客户端,会在cookie过期之前保存在浏览器缓存中。
以后的每一次请求,浏览器都会携带此Cookie来表明自己的身份。
Cookie的限制以及应用
在set-cookie的时候,会有一个domain的域名字段,表示该cookie只在访问该域名时会被携带(图中为.jd.com,意为访问jd.com下的所有二级域名都会被携带)。
用处:可以在一级域名下的所有子域名的网站共用一个登录态。
疑惑:一些cookie的expires(过期时间)为session,表示会话结束就删除cookie,为什么关掉浏览器还是会保存此cookie?
cookie的expires(过期时间)为session,表示在浏览器关闭之后就将cookie删除,但是chrome浏览器会默认保存cookie,需要设置“退出 Chrome 时清除 Cookie 及网站数据”,退出浏览器之后所有的cookie信息都会被删除。这个时候cookie的过期时间就跟浏览器会话过期时间有关。
Cookie的写入规则
问题描述:在 a.jd.com 网址控制台中写入一个Cookie:
document.cookie='myname=zhangsan;path=/;domain=b.jd.com';
不生效!!只能向当前域、子域写cookie。
因为不管是js还是服务器设置Cookie,只能向当前域、更高级域写入Cookie。即a.jd.com只能向jd.com和a.jd.com写入Cookie(只能操作自己域相关Cookie,别人的不能动)。
那关于b.jd.com的Cookie或者a.taobao.com的Cookie是怎么写入的呢?
通过向b.jd.com服务器发送请求,b.jd.com服务器就可以通过set-cookie字段设置有关于自己域名下b.jd.com的Cookie。(因为是在它的当前域)
注:application中不在当前域、更高域下的Cookie是看不到的(火狐),这是不同浏览器的实现方式不一样,但是其实都设置成功了,在浏览器的Cookie中都可以看到。
Cookie属性
打开控制台Application中的cookies,就可以看到各个cookie字段的属性。
Name
cookie的名字,同一个域名下的cookie的名字不能相同,不然会被覆盖掉。
Value
表示cookie的值,由于cookie规定是名称/值是不允许包含分号,逗号,空格的,所以为了不给用户到来麻烦,考虑服务器的兼容性,任何存储cookie的数据都应该被编码。
Domain
表示该cookie被绑定到某一个域名下,只要访问该域名,就会携带该cookie。 .baidu.com对于baidu.com的所有子域名都有效。但是相同一级域名下的不同二级域名之间是不能相互交换cookie的,比如domain为a.baidu.com下的cookie与domain为b.baidu.com下的cookie是不能共用的。
Path
对于指定域名下的某一个路径,发送该cookie,其他路径则不发送。 默认为‘/’,对于该域下的所有路径都使用该cookie。 可指定某一个cookie只有路径为 baidu.com/path/ 的时候才可发送。
Expires
该cookie的到期时间。默认情况下,cookie会在会话结束后就被删除,但是也可以设置成就算浏览器关闭也依然保存在浏览器内存中。
除了代码中设置的过期时间,cookie的保存还会收到浏览器自定义设置的影响。上文有提到。
Secure
在此字段为true时,表示该cookie只有在使用https访问的时候才会发送。
例:cookie只会发送给xxx.baidu.com 而不会发送给 xxx.baidu.com
HttpOnly
此字段设置为true时,表示该cookie不能通过js去获取(document.cookie),可以有效的防止xss(跨站脚本攻击)。
SameSite
这个属性是关于浏览器如何处理第三方cookie的,比如我们在跨站跳转链接时,是否可以携带第三方cookie? 由于之前在项目当中遇到过关于SameSite的问题,这里决定详细的说一下这个字段。
Cookie缺点
- 容量有限:Cookie 的体积上限只有4KB,只能用来存储少量的信息。
- 性能缺陷:Cookie 紧跟域名,不管域名下面的某一个地址需不需要这个 Cookie ,请求都会携带上完整的 Cookie,这样随着请求数的增多,其实会造成巨大的性能浪费。
- 安全缺陷:由于 Cookie 以纯文本的形式在浏览器和服务器中传递,很容易被非法用户截获,然后进行一系列的篡改,在 Cookie 的有效期内重新发送给服务器,这是相当危险的。另外,在HttpOnly为 false 的情况下,Cookie 信息能直接通过 JS 脚本来读取。