文章目录
1.我们看到的cookie
1.1 cookie初体验
- 创建一个网址,网址为http://127.0.0.1:5500/ajax/cookie.html,这个网页设置了几个cookie:
- chrome浏览器开发模式中,点击Appliction栏—>选中cookies,这里会看到如下图所示的界面
说明:
1)左边栏Cookies下方会列举当前网页中设置过cookie的域都有哪些
2)而右侧区域显示的就是某个域下具体的 cookie 列表,对应上图就是当前域下设置的3个cookie
1.2 发送Ajax请求时Request Header中cookie的自动添加
- 当我在这个网页中发送Ajax请求到服务器时(注意,并不是跨域请求,对于跨域请求的cookie,下文再进行讲述),那么此时请查看请求中Request Header中的相关信息,你会发现在Request Header中自动添加了cookie字段(这是浏览器自动帮你加上的)
- 由于这个请求最终会发送到服务器上,那么这个服务器就会接收到Request Header中的浏览器所设置的cookie
总结一下上面的流程:
浏览器设置cookie—>cookie被自动添加到Request Header中—>服务器接收到cookie
思考:
1.cookie时怎样工作的?cookie为什么会自动添加到Request Header中?什么样的数据适合放在cookie中?
2.cookie有哪些属性?
3.cookie是怎样设置的?(服务器端和客户端)
4.cookie怎样进行增删改查?
让我们带着问题继续往下看吧!
2.cookie是怎样工作的?
- 当网页要发送请求时,浏览器会先检查是否有相应的cookie,有则自动添加到Request Header中的cookie字段中。这些都是浏览器自动帮我们做的。
- 基于上原理,存储再cookie中的数据,每次都会被浏览器自动放在http请求中,如果这些数据并不是每个请求都需要发给服务端,那么浏览器的自动处理无疑时增加了网络开销。因此,对于存储再cookie上数据的设置,通常时每个请求都需要发给服务器的(比如身份认证信息)
- 在出现localStorage之前,cookie被滥用做了存储工具。当然,cookie标准还是做了一些限制的:每个域名下的cookie的大小为4kb,每个域名下的cookie最多为20个(可能不同浏览器厂商会有些不同)
3. cookie的属性有哪些
3.1 expries(失效日期)
- cookie的失效日期(在新的协议http/1.1中expries已经为max-age代替)
3.2domain:域名
3.3 path:路径
- domain和path两者加起来就构成了URL,domain和path一起来限制cookie能被哪些url访问
- 一句话概括:某cookie的 domain为“baidu.com”, path为“/ ”,若请求的URL(URL 可以是js/html/img/css资源请求,但不包括 XHR 请求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/ ”或子路径“/home”、“/home/login”,则浏览器会将此 cookie 添加到该请求的 cookie 头部中。
- 所以domain和path两个选项共同决定了cookie何时被浏览器自动添加到请求头部发送出去。如果没有设置这两个选项,则会使用默认值。默认值就是domain为设置该cookie网页所在的域名,path默认值为设置该cookie的网页所在的目录
- 特别说明:当发送跨域xhr请求时,即是请求url的域名和路径都满足cookie的domain和path,默认情况下cookie也是不会自动被添加到Request Header中的(详细说明在下文)
2.4 secure
用来设置cookie旨在安全的请求中发送,设置了secure的cookie,在开发者工具中,cookie向后面会有个勾(HTTPS或其他安全协议,在HTTP中部起效)
- 默认情况下,cookie属性secure为空,即不管是HTTPS协议还是HTTP协议的请求,cookie都会发送至服务器
- 但是注意,secure只是限定了是否发送,并不限定你是否还能看到设置的cookie(即设置了secure的cookie,我们仍然可以看到)
下面我们设置一个 secure类型的 cookie:
document.cookie = "name=huang; secure";
之后你就能在控制台中看到这个 cookie 了,如下图所示:
这里有个坑需要注意下:
如果想在客户端即网页中通过 js 去设置secure类型的 cookie,必须保证网页是https协议的。在http协议的网页中是无法设置secure类型cookie的。
2.5 httpOnly
- 这个选项设置cookie是否能通过js去反问,默认情况下,cookie不会带httpOnly选项(即为空),所以默认情况下,客户端是可以通过js代码去访问的(包括读取、修改、删除)
- 当设置了httpOnly之后,客户端则不能通过js代码去访问
- 注意,客户端是不能通过js代码设置httpOnly类型的cookie的,这种类型的cookie只能由服务端来设置
那我们在页面中怎么知道哪些cookie是httpOnly类型的呢?看下图:
凡是httpOnly类型的cookie,其 HTTP 一列都会打上√,如上图中的PA_VTIME。你通过document.cookie是不能获取的,也不能修改PA_VTIME的。
——httpOnly与安全
从上面介绍中,大家是否会有这样的疑问:为什么我们要限制客户端去访问cookie?其实这样做是为了保障安全。
试想:如果任何 cookie 都能被客户端通过document.cookie获取会发生什么可怕的事情。当我们的网页遭受了 XSS 攻击,有一段恶意的script脚本插到了网页中。这段script脚本做的事情是:通过document.cookie读取了用户身份验证相关的 cookie,并将这些 cookie 发送到了攻击者的服务器。攻击者轻而易举就拿到了用户身份验证信息,于是就可以摇摇大摆地冒充此用户访问你的服务器了(因为攻击者有合法的用户身份验证信息,所以会通过你服务器的验证)。
4. 如何设置cookie?
说明:cookie可以由服务端来设置,也可以由客户端来设置
4.1 服务端设置cookie
- 首先,不管你是请求一个资源文件(如html/css/js/图片),还是发送一个ajax请求,服务端都会返回response,而Response Header中有一项叫做set-cookie,是服务端专门用来设置cookie的。如下图所示,服务端返回的Response Header中有5个set-cookie字段,每个字段对应一个cookie(注意不能将多个cookie放在一个set-cookie字段中,每个cookie还设置了相应的属性选项)
注意:
-
一个set-Cookie字段只能设置一个cookie,当你要想设置多个 cookie,需要添加同样多的set-Cookie字段。
-
服务端可以设置cookie 的所有选项:expires、domain、path、secure、HttpOnly
4.2 客户端设置cookie
在网页中客户端中我们可以通过js代码来设置cookie,如下:
如我在当前打开的网页中http://127.0.0.1:5500/ajax/cookie.html,在js中设置如下(此时我的域名为127.0.0.1)
document.cookie = "name=John";
再执行下面代码:
document.cookie="age=12; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";
查看浏览器,如下图,新增的cookie设置成功了,而且expires、demain、path都是你设定的值
注意:
- 客户端可以设置cookie 的下列选项:expires、domain、path、secure(有条件:只有在https协议的网页中,客户端设置secure类型的 cookie 才能成功),但无法设置HttpOnly选项。
4.3 用 js 如何设置多个 cookie
当要设置多个cookie时, js 代码很自然地我们会这么写
document.cookie = "name=Jonh; age=12; class=111";
但你会发现这样写只是添加了第一个cookie“name=John”,后面的所有cookie都没有添加成功。所以最简单的设置多个cookie的方法就在重复执行document.cookie = “key=name”,如下:
document.cookie = "name=Jonh";
document.cookie = "age=12";
document.cookie = "class=111";
5. 如何修改、删除cookie?
5.1 修改cookie
- 要想修改一个cookie,只需要重新赋值就行,旧的值会被新的值覆盖。但要注意一点,在设置新cookie时,path/domain这几个选项一定要旧cookie 保持一样。否则不会修改旧值,而是添加了一个新的 cookie。
5.2 删除cookie
- 删除一个cookie 也挺简单,也是重新赋值,只要将这个新cookie的expires 选项设置为一个过去的时间点就行了。但同样要注意,path/domain/这几个选项一定要旧cookie 保持一样。
6.cookie 编码
cookie其实是个字符串,但这个字符串中逗号、分号、空格被当做了特殊符号。所以当cookie的 key 和 value 中含有这3个特殊字符时,需要对其进行额外编码,一般会用escape进行编码,读取时用unescape进行解码;当然也可以用encodeURIComponent/decodeURIComponent或者encodeURI/decodeURI(三者的区别可以参考这篇文章)
var key = escape("name;value");
var value = escape("this is a value contain , and ;");
document.cookie= key + "=" + value + "; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";
6. 跨域请求中的cookie
说明:
- 前面提及到的cookie会自动被添加到Request Header上针对的时非跨域的请求,当是在跨域请求情况下,cookie作为一种credentials信息,是不会自动传送到服务端的,必须进行额外的设置。
原因:
- 在CORS标准中做了规定,默认情况下,浏览器在发送跨域请求时,不萌发送任何认证信息(credentials),认证信息如有(cookies、HTTP authentication schemes“,除非xhr.withCredentials为true,xhr.withCredentials默认值为false)
解决:
-
服务端必须手动设置
xhr.withCredentials=true
-
且服务端也必须允许
request
能携带认证信息
即Response Header中包含Access-Control-Allow-Credentials:true
-
这样一来,浏览器才会自动将cookie加载Request Header中
另外,要特别注意的一点。一档跨域request能够携带认证信息,服务端一定不能将Access-Control-Allow-Origin
设置为*
,而必须设置为请求页面的域名
参考文章: