cookie是服务器贴到客户端, 由客户端维护的状态片段, 并在下一次向同一个服务器发送请求时一同发送这段数据. cookie常用于保存用户的登录信息或其他不便于保存在服务器端数据库的size较小的数据.

cookie简单介绍

HTTP请求是stateless的, 下一次请求无法得知上一次HTTP请求所包含的状态数据, cookie使得HTTP请求变得stateful.

过去常使用cookie来存储客户端的数据, 但实际上这样的用法并不是那么合适, 因为cookie会跟着每一次http请求一同被发送, 对web app的性能有较大的影响.

比较推荐的方式是使用Web storage API(localStorage 和 sessionStorage)或IndexDB.

创建cookie

服务器接受到HTTP请求之后, 可以在传送回HTTP响应的报文中添加Set-Cookie首部. 使用Set-Cookie创建的cookie一般存储在客户端(浏览器), 然后在客户端下一次向同一个服务器发送请求时一并发送cookie. 可以对cookie设置过期时间, 域名, 路径, secure, HttpOnly等属性.

Node.js下使用”Set-Cookie”:

1
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);

cookie的类型有两种, 一是会话cookie, 关闭浏览器cookie就被删除, 不对其设置ExpiresMax-Age属性, 该cookie就是会话cookie, 不过浏览器可以使用session restoring把会话cookie转化为持久cookie.

持久cookie存储在硬盘, 计算机重启之后依然存在. 在超出Expires日期或Max-Age的时间后才被删除.

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

cookie还有secure属性, 添加了secure属性的cookie只有在HTTPS或SSL协议下才会被发送到服务器. 不过尽管声明secure属性, 一些敏感信息还是不应该存储在cookie中, 因为cookie本身是不安全的, 虽然加了secure属性, 但是无法真正保护cookie信息. 从Chrome 52和Firefox 52开始, http协议下的站点不允许在cookie中添加secure属性. 在默认情况下, 通过HTTPS协议传输的请求默认包括secure属性.

HttpOnly也是cookie中的一个重要属性, 在cookie中添加这一属性可以防止XSS攻击, 因为添加该属性后, 就不能通过Document.cookie API获取cookie的值, cookie只能被发送到服务器. 维持服务器端会话的cookie没有必要通过JavaScript获取, 因此可以对这种类型的cookie设置HttpOnly属性.

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

cookie的作用域

cookie存在作用域, domain和path属性定义了cookie的作用域: 即cookie应该被发送到哪一个URL.

domain属性中声明了哪些host可以接收到该cookie, 如果不声明domain的属性值, 其默认值就是document.location.host的值, 但不包括其下的子域名. 如果声明了domain属性值, 其下的子域名也会被包括.

path属性则声明URL的路径, 默认值为发送Set-Cookie首部所在URL的path值. 如果设置了path=/docs, 任何以/docs为开头的path均会被包括, 如:

  • /docs
  • /docs/Web/
  • /docs/Web/HTTP
  • /docsforcookies

如果想要重写某个cookie, 除了匹配name之外, 还需要匹配需要被重写的cookie的domain, path的值. 否则只会将该cookie添加到document.cookie字符串中.

假设现在有个cookie: foo=hello; 已知其domain值为.icyfish.github.io, path值为/. 我们要将该cookie值修改为foo=hi:

1
2
3
4
5
// ✖️错误的方式✖️
document.cookie = "foo=hi";

// ✔️应该这样做✔️
document.cookie = "foo=hi; path=/;domain=.icyfish.github.io";

Subcookies

由于每个域名下可使用的cookie数量有限制, 因此开发者想出了使用subcookie的方法以突破这个限制, 常见的形式是:

name=a=b&c=d&e=f&g=h

这样的话, 单个cookie就能够存储多个名值对信息, 不会超过浏览器cookie数量限制. 不过这样做有一个缺陷, 需要自己实现一种解析方式以解析这种形式的cookie. 一些服务端框架, 例如YUI的Cookie辅助工具, 就支持读写subcookie.

  • 服务器利用cookie实现session(会话), session指的是客户端(浏览器)与服务器之间处于激活状态的一次连接所关联的一系列数据.

  • 一般来说, 每个web app的cookie, 对于每一次session, 都存在一个独一无二的识别码, 通常叫做session id.

  • Web框架Ruby on Rails负责处理大部分session和cookie的相关内容:

    • Rail提供了一个session对象, 可以在其中存储任何你想要存储的数据.

      • 同一个客户端之后的请求可以获取存储在其中的数据
    • 在每一次请求之始, Rails会自动检查session cookie的情况

      • 如果cookie存在, 就据此来查找session数据
      • 如果cookie不存在, 创建新的session和cookie
    • 请求结束时, 保存session数据, 以便未来的请求获取这些数据

  • 管理session状态:

    • 方法1: 将session状态保存在服务器内存中
      • 获取数据快速高效
      • session数据可能过大影响服务器性能
      • 影响web服务器之间的负载均衡
    • 方法2: 将session 状态保存在硬盘的文件中
    • 方法3: 将session 状态保存在数据库
    • 大部分web框架会提供方法用以控制session的存储:
      • 提供一个对象存储和恢复session数据
  • 服务器最终会删除过期的session数据


参考