聊一聊cookie

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设置为*,而必须设置为请求页面的域名

参考文章:

Guess you like

Origin blog.csdn.net/weixin_46872121/article/details/111716240