cookie基础
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就被删除, 不对其设置Expires
或Max-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 | // ✖️错误的方式✖️ |
Subcookies
由于每个域名下可使用的cookie数量有限制, 因此开发者想出了使用subcookie的方法以突破这个限制, 常见的形式是:
name=a=b&c=d&e=f&g=h
这样的话, 单个cookie就能够存储多个名值对信息, 不会超过浏览器cookie数量限制. 不过这样做有一个缺陷, 需要自己实现一种解析方式以解析这种形式的cookie. 一些服务端框架, 例如YUI的Cookie辅助工具, 就支持读写subcookie.
cookie 和 session
服务器利用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数据
- 方法1: 将session状态保存在服务器内存中
服务器最终会删除过期的session数据
参考