cookie的介绍和使用

猿友 2021-02-22 14:01:19 浏览数 (10006)
反馈

一、概述

Cookie 是服务器保存在浏览器的一小段文本信息,一般大小不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。

Cookie 主要保存状态信息,以下是一些主要用途。

  • 对话(session)管理:保存登录、购物车等需要记录的信息。
  • 个性化信息:保存用户的偏好,比如网页的字体大小、背景色等等。
  • 追踪用户:记录和分析用户行为。

Cookie 不是一种理想的客户端储存机制。它的容量很小(4KB),缺乏数据操作接口,而且会影响性能。客户端储存应该使用 Web storage API 和 IndexedDB。只有那些每次请求都需要让服务器知道的信息,才应该放在 Cookie 里面。

有关对Web storage的介绍,可以看这篇博客:sessionStorage 和 localStorage 的使用

每个 Cookie 都有以下几方面的元数据。

  • Cookie 的名字
  • Cookie 的值(真正的数据写在这里面)
  • 到期时间(超过这个时间会失效)
  • 所属域名(默认为当前域名)
  • 生效的路径(默认为当前网址)

举例来说,用户访问网址 ​www.example.com​,服务器在浏览器写入一个 Cookie。这个 Cookie 的所属域名为 ​www.example.com​,生效路径为根路径 ​/​。

如果 Cookie 的生效路径设为​ /user​,那么这个 Cookie 只有在访问​ www.example.com/use​r 及其子路径时才有效。以后,浏览器访问某个路径之前,就会找出对该域名和路径有效,并且还没有到期的 Cookie,一起发送给服务器。

用户可以设置浏览器不接受 Cookie,也可以设置不向服务器发送 Cookie。 window.navigator.cookieEnabled 属性返回一个布尔值,表示浏览器是否打开 Cookie 功能。

window.navigator.cookieEnabled // true

document.cookie​ 属性返回当前网页的 Cookie。

不同浏览器对 Cookie 数量和大小的限制,是不一样的。一般来说,单个域名设置的 Cookie 不应超过30个,每个 Cookie 的大小不能超过4KB。超过限制以后,Cookie 将被忽略,不会被设置。

两个网址只要域名相同,就可以共享 Cookie。 注意,这里不要求协议相同。也就是说,​http://example.com ​设置的 Cookie,可以被 ​https://example.com​ 读取。

二、Cookie 与 HTTP 协议

Cookie 由 HTTP 协议生成,也主要是供 HTTP 协议使用。

1、HTTP 回应:Cookie 的生成

服务器如果希望在浏览器保存 Cookie,就要在 HTTP 回应的头信息里面,放置一个 ​Set-Cookie​ 字段。

Set-Cookie:foo=bar

上面代码会在浏览器保存一个名为 foo 的 Cookie,它的值为 bar。

HTTP 回应可以包含多个 ​Set-Cookie​ 字段,即在浏览器生成多个 Cookie。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

除了 Cookie 的值,Set-Cookie字段还可以附加 Cookie 的属性。一个Set-Cookie字段里面,可以同时包括多个属性,没有次序的要求。

Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

在这里插入图片描述

2、HTTP 请求:Cookie 的发送

浏览器向服务器发送 HTTP 请求时,每个请求都会带上相应的 Cookie。也就是说,把服务器早前保存在浏览器的这段信息,再发回服务器。这时要使用 HTTP 头信息的 ​Cookie​ 字段。

// 会向服务器发送名为 foo的 Cookie,值为 bar。
Cookie: foo=bar

// Cookie字段可以包含多个 Cookie,使用分号(;)分隔。
Cookie: name=value; name2=value2; name3=value3

下面是一个例子。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

在这里插入图片描述

三、Cookie 的属性

1、Expires,Max-Age

Expires​ 属性指定一个具体的到期时间,到了指定时间以后,浏览器就不再保留这个 Cookie。它的值是 UTC 格式,可以使用​Date.prototype.toUTCString()​ 进行格式转换。

如果不设置该属性,或者设为null,Cookie 只在当前会话(session)有效,浏览器窗口一旦关闭,当前会话结束,该 Cookie 就会被删除。另外,浏览器根据本地时间,决定 Cookie 是否过期,由于本地时间是不精确的,所以没有办法保证 Cookie 一定会在服务器指定的时间过期。

Max-Age​ 属性指定从现在开始 Cookie 存在的秒数,比如 60 * 60 * 24 * 365(即一年)。过了这个时间以后,浏览器就不再保留这个 Cookie。

如果同时指定了 ​Expires​ 和 ​Max-Age​,那么​ Max-Age​ 的值将优先生效。

如果 ​Set-Cookie​ 字段没有指定​Expires​或​Max-Age​属性,那么这个 Cookie 就是 Session Cookie,即它只在本次对话存在,一旦用户关闭浏览器,浏览器就不会再保留这个 Cookie。

使用 Node 创建一个服务器来模拟演示:

const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)
  
  const html = fs.readFileSync('test.html', 'utf8')
  response.writeHead(200, {
    'Content-Type': 'text/html',
    'Set-Cookie': ['id=123;max-age=2', 'abc=456;HttpOnly']
  })
  response.end(html)

}).listen(8888)

console.log('http://127.0.0.1:8888')

在这里插入图片描述

在这里插入图片描述

2、Domain,Path

Domain​属性指定浏览器发出 HTTP 请求时,哪些域名要附带这个 Cookie。

  • 如果没有指定该属性,浏览器会默认将其设为当前域名,这时子域名将不会附带这个 Cookie。比如,​example.com​ 不设置 Cookie 的domain属性,那么 sub.example.com 将不会附带这个 Cookie。
  • 如果指定了domain属性,那么子域名也会附带这个 Cookie。如果服务器指定的域名不属于当前域名,浏览器会拒绝这个 Cookie。
  • 一句话总结:Domain标识指定了哪些主机可以接受Cookie。如果不指定,默认为当前主机(不包含子域名)。如果指定了Domain ,则一般包含子域名。

Path​属性指定浏览器发出 HTTP 请求时,哪些路径要附带这个 Cookie。只要浏览器发现,Path属性是 HTTP 请求路径的开头一部分,就会在头信息里面带上这个 Cookie。比如,PATH属性是 ​/​,那么请求 ​/docs ​路径也会包含该 Cookie。当然,前提是域名必须一致。

3、Secure,HttpOnly

Secure ​属性指定浏览器只有在加密协议 HTTPS 下,才能将这个 Cookie 发送到服务器。另一方面,如果当前协议是 HTTP,浏览器会自动忽略服务器发来的Secure属性。该属性只是一个开关,不需要指定值。如果通信是 HTTPS 协议,该开关自动打开。

HttpOnly​ 属性指定该 Cookie 无法通过 JavaScript 脚本拿到,主要是 ​document.cookie​ 属性、​XMLHttpRequest​ 对象和 ​Request API​ 都拿不到该属性。这样就防止了该 Cookie 被脚本读到,只有浏览器发出 HTTP 请求时,才会带上该 Cookie。出于安全考虑。

四、document.cookie

document.cookie​ 属性用于读写当前网页的 Cookie。读取的时候,它会返回当前网页的所有 Cookie,前提是该 Cookie 不能有HTTPOnly属性。

document.cookie // "foo=bar;baz=bar"

上面代码从​ document.cookie ​一次性读出两个 Cookie,它们之间使用分号分隔。必须手动还原,才能取出每一个 Cookie 的值。这就是cookie存取数据不方便的地方,它没有完善的存取数据的api让我们用,我们必须手动的从中提取自己需要的数据。

document.cookie​ 属性是可写的,可以通过它为当前网站添加 Cookie。写入的时候,Cookie 的值必须写成​key=value​的形式。注意,等号两边不能有空格。​ document.cookie​一次只能写入一个 Cookie,而且写入并不是覆盖,而是添加。

document.cookie = 'fontSize=14';

// 最终只会有 test1=456 被写进去
document.cookie = 'test1=456;hahah=123'

document.cookie ​读写行为的差异(一次可以读出全部 Cookie,但是只能写入一个 Cookie),与 HTTP 协议的 Cookie 通信格式有关。

  • 浏览器向服务器发送 Cookie 的时候,Cookie字段是使用一行将所有 Cookie 全部发送;
  • 服务器向浏览器设置 Cookie 的时候,​Set-Cookie​字段是一行设置一个 Cookie。

删除一个现存 Cookie 的唯一方法,是设置它的​ expires​ 属性为一个过去的日期。

document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';

五、参考资料

HTTP cookies 详解


0 人点赞