浏览器Cookie详解

一、了解 Cookie

  • Cookie 最开始被设计出来是为了弥补HTTP状态管理上的不足HTTP 协议是一个无状态协议,客户端向服务器发请求,服务器返回响应,故事就这样结束了,但是下次发请求如何让服务端知道客户端是谁呢?这种背景下,就产生了 Cookie。
  • cookie 存储在客户端: cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。因此,服务端脚本就可以读、写存储在客户端的cookie的值。
  • cookie 是不可跨站的: 每个 cookie 都绑定在特定的域名下(绑定域名下的子域都是有效的),无法在别的域名下获取使用,同域名不同端口也允许共享

可以在浏览器控制台的 Application 面板查看Cookie:

Cookie 的数据流转

  1. 在首次访问网站时,浏览器发送请求中并未携带Cookie。
  2. 浏览器看到请求中未携带Cookie,在HTTP的响应头中加入Set-Cookie。
  3. 浏览器收到Set-Cookie后,会将Cookie保存下来
  4. 下次再访问该网站时,HTTP请求头就会携带Cookie。
设置Cookie
携带Cookie

Cookie都是name=value的结构,具体格式如下:

Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"

二、检测cookie是否启用

有些用户为了避免隐私泄露会在它们的浏览器中禁用cookie。因此,在js代码使用cookie前,首先要确保cookie是启用的。可以用navigator.cookieEnabled属性来判断,如果值为true,则当前cookie是启用的;反之则是禁用的(但是,只具备“当前浏览器会话生命周期”的非持久化cookie仍然是启用的)。

三、cookie属性:有效期和作用域

cookie默认的有效期很短暂,它只能维持在Web浏览器的会话期间,一旦用户关闭浏览器,cookie保存的数据就丢失了。要注意的是,这与sessionStorage的有效期还是有区别的:cookie的作用域不是局限在浏览器的单个窗口中,它的有效期和整个浏览器进程而不是单个浏览器窗口的有效期一致。如果想要延长cookie的有效期,可以通过设置max-age属性。一旦设置了有效期,浏览器就会将cookie数据存储在一个文件中,并且直到过了指定的有效期才会删除该文件。

cookie的作用域是通过文档源和文档路径来确定的。该作用域通过cookie的path和domain属性可配置。

四、Cookie常见属性

属性说明
name=value键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型(name 不区分大小写)
- 如果值为 Unicode 字符,需要为字符编码。
- 如果值为二进制数据,则需要使用 base64 编码。
domain

Cookie生效的域名,即Cookie在哪个网站生效。默认当前访问域名。

例如我们在a.jzplp.com下设置的Cookie,就只在这个域名下生效。但是如果我们设置了domain=jzplp.com,则该Cookie可以在jzplp.com下的任何域名内生效。比如:jzplp.com,a.jzplp.com, b.jzplp.com。

domain 只能设置为当前服务器的域。

path

有时候,我们希望Cookie仅仅在部分路径下生效,就可以使用Path进行限制。这里的路径就是网站的路由。默认的path=/,即在所有路径下生效。 如果设置了path=/abc,则只在/abc路径下生效。比如:

  • jzplp.com 不生效
  • jzplp.com/abc 生效
  • jzplp.com/abc/def 生效
  • jzplp.com/qaz 不生效
  • jzplp.com/qaz/abc 不生效
expires

过期时间(GMT时间格式),当浏览器端本地的当前时间超过这个时间时,Cookie便会失效。

如果客户端和服务器时间不一致,使用expires就会存在偏差。
一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,cookie会被删除。

Expires格式:Expires=Wed, 21 Oct 2015 07:28:00 GMT。

Max-age

cookie 存活时间,单位秒。如果为正数,则该 cookie 在 maxAge 秒后失效。如果为负数,该 cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。如果为 0,表示删除该 cookie 。默认为 -1。
- 优先级高于 expires 

HttpOnly如果给某个 cookie 设置了 httpOnly 属性,则无法通过js读写该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 CSRF 攻击,不是绝对的安全
secure

该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。
当 secure 值为 true 时,cookie 在 HTTP 中是无效的。

SameSite是否允许跨站请求时发送Cookie
Priority

当Cookie的数量超过限制时,路蓝旗会清除一部分Cookie。清除哪些合适呢?Priority属性用来定义Cookie的优先级,低优先级的Cookie会优先被清除。

Priority属性有三种: Low, Medium, High。

cookie集合中的每个cookie都拥有这些属性,而且每个cookie的这些属性都是独立分开的,各自控制各自的cookie。

五、cookie的局限性

1. 每个域名下cookie个数限制

  • Chrome和Safari没有做硬性限制
  • Firefox最多50个cookie
  • IE7和之后的版本最后可以有50个cookie
  • IE6或更低版本最多20个cookie

RFC 2965标准不允许浏览器保存超过300个cookie,为每个Web服务器保存的cookie数不能超过20个(是对整个服务器而言,而不仅仅指服务器上的页面和站点),而且,每个cookie保存的数据不能超过4KB。实际上,现代浏览器允许cookie总数超过300个,但是部分浏览器对单个cookie大小仍然有4KB的限制。

六、客户端对Cookie的存取

1. 读取cookie:

可以用 document.cookie 获取当前页面可用的cookie集合,其返回的值是一个字符串,该字符串都是由一系列键/值对组成,不同键/值对之间通过“分号和空格”分开。例如:

document.cookie;
// "name1=value1; name2=value2"

这些返回的cookie值并不包含键/值以外的其他cookie属性。

2. 设置cookie:

document.cookie = `name=${encodeURIComponent(name)}; max-age=1000;`;

name这个cookie会被添加到现有的cookie集合中。

由于cookie的键/值中的值是不允许包含分号、逗号和空白符,因此,在存储前一般可以采用 encodeURIComponent() 函数对值进行编码。相应的,读取cookie值的时候要用 decodeURIComponent() 函数解码。

3. 更新cookie

要改变cookie的值,需要使用相同的名字、路径和域,但是新的值重新设置cookie的值。同样地,设置新 max-age 属性就可以改变原来的cookie的有效期。

4. 删除cookie

要删除一个cookie,需要使用相同的名字、路径和域,然后指定一个任意(非空)的值,并且将 max-age 属性指定为0,再次设置cookie。

七、封装对Cookie的操作

由于cookie的读写非常不方便,我们可以自己封装一些函数来处理cookie。

1. 获取全部cookie,返回一个对象

function getAllCookies() {
  let cookies = {};
  const all = document.cookie;
  if (all) {
    const list = all.split('; ');
    list.forEach(cookie => {
      const cookieArr = cookie.split('=');
      const name = cookieArr[0];
      cookies[name] = decodeURIComponent(cookieArr[1]);
    });
  }
  return cookies;
}

2. 获取单个cookie,设置、删除cookie

class cookieUtils {
  get(name) {
    var arr,
      reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
    if ((arr = document.cookie.match(reg))) return decodeURIComponent(arr[2]);
    else return null;
  }
 
  set(name, value, daysToLive) {
    let cookie = `${name}=${encodeURIComponent(value)}`;
    // daysToLive指天数
    if (typeof daysToLive === 'number') {
      cookie += `; max-age=${daysToLive * 24 * 60 * 60}`;
    }
    document.cookie = cookie;
  }
 
  delete(name) {
    var date = new Date();
    date.setTime(date.getTime() - 10000);
    document.cookie = name + "=-1;expires=" + date.toGMTString();
  }
}
 
export default new cookieUtils();

在Chrome控制台Application 的 Cookies 里可以对 cookie 进行读写操作。

移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token。

八、服务器端设置cookie示例(Node)

var http = require('http');
var fs = require('fs');
 
http.createServer(function(req, res) {
    res.setHeader('status', '200 OK');
    res.setHeader('Set-Cookie', 'isVisit=true;domain=.yourdomain.com;path=/;max-age=1000');
    res.write('Hello World');
    res.end();
}).listen(8888);
 
console.log('running localhost:8888')

参考

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值