HTTP-Cookie

HTTP状态

HTTP协议是一个无状态的协议,所有内容都位于来往的Request/Response报文之中。

但是在某些时候,我们希望能够识别用户身份,追踪用户状态/浏览路径来提供一些服务:

  1. 个性化的问候和欢迎
  2. 精准的商品推荐
  3. 存储用户信息,如地址和信用卡信息
  4. 会话状态,例如购物车

识别用户身份

HTTP首部

除了Cookie外,还有一些其他的HTTP首部可以用来发送客户端信息,可以作为了解

  1. From: 字段携带用户Email,因为隐私和对垃圾邮件的顾虑,基本没浏览器会发送该字段
  2. User-Agent: 包含了浏览器版本,操作系统信息等内容,用来定制操作系统相关的信息时很有用
  3. Referer: 提供了跳转之前的网站URL,可以标示访问者的来源

IP地址标识

HTTP无法确定用户的IP地址,但是通过系统提供的Socket API可以从TCP报文中获取客户端的IP地址。

利用IP地址来确认用户身份具有非常大的缺点:

  1. IP地址标识了机器,公共计算机可能被不同的用户使用
  2. 许多用户通过NAT技术来接入互联网,IP地址后很可能隐藏了许多不同用户
  3. ISP(因特网服务提供商)的动态IP,代理网关等,都可能导致用户IP的变化

用户登陆机制

网站可以使用包括HTTP内建登陆机制在内的登陆机制来识别用户身份

登陆机制是一种比较完善,安全的状态记录机制,但是对于用户来说,依然不够友好,对于许多轻量级应用(如精准广告投放,购物车),让用户记录一串密码账号是非常糟糕并且不现实的

胖URL

胖URL是一种将用户的身份写在URL里的状态保存方法。当用户第一次连接时,在URL里加入一些特殊内容来标示身份,之后呈现给用户的所有HTML页面的URL连接都被渲染为包含了该ID的特殊URL。

通过胖URL,亚马逊这样的电商可以追踪用户本次连接访问的商品,实现购物车,精准推荐等功能

如之前的这些解决方法,胖URL也有着许多缺点:

  1. 无法共享的URL:共享会将自己的身份ID发出去,导致隐私泄露
  2. 加重服务器荷载,服务器需要实时渲染大量不同的HTML页面
  3. 代码难于书写维护,用户容易点击普通URL从而失去身份
  4. 不持久,当用户离开会话再次连接,无法确认上次的身份

Cookie

Cookie是在HTML5的LocalStorageSessionStorage之前最佳的持久会话实现方式,所有主要浏览器都支持该功能,其将会话状态保存在HTTP首部中

Cookie是浏览器和服务器实现的一种首部,而不是HTTP/1.1规范里的

规范

Cookie首部的规范有版本0和版本1两个标准,后者是对前者的加强和扩充

本地Cookie的存储则根据浏览器的不同实现不同,一般作为一个表存储在文件里

结构

Cookie版本0的核心是两个分别在请求和响应中出现的首部:

  1. Set-Cookie: name=value [; expires=date] [; path=path] [; domain=domain] [;secure]
  2. Cookie: name=value1 [; name2 = value2]

服务器通过Set-Cookie首部设置 Key-Value Pair,其可选项可以设置一些参数:

  1. Expires: 不设置过期时间意味着关闭浏览器后消失(会话生命周期)
  2. Domain: 只向指定域发送Cookie,至少要2-3个dot,不允许.com这类用法,不设置则默认为响应的服务器的主机名
  3. Path: 在Domain的基础上,与该路径匹配,如/foo/foo/a, /foo/b匹配,默认为当前响应的路径
  4. Secure: 如果设置该属性,则只有在HTTPS协议下发送该Cookie

浏览器在上述参数符合的情况下将在请求头附带Cookie首部传递存储的Cookie

在Cookie版本1加入了一些其他首部,具体可以查询标准

会话过程

服务器通常通过这样的一个过程来完成Cookie的附加:

  1. 客户端发送请求到服务器
  2. 服务器响应302重定向客户端到Cookie附加页面
  3. 客户端发送请求到重定向页面
  4. 重定向页面附加Cookie并再次发送302重定向到正常入口
  5. 客户端再次发送请求到重定向页面
  6. 服务器响应,进入正常入口,通过Cookie追踪身份

缺点

Cookie是目前Client/Server通信最好的方式(LocalStorage必须依靠其他方法向服务器通信), 但是依然有许多缺点:

  1. 大小与个数受限, 通常为4K
  2. 存在风险, 用户和恶意程序可能篡改Cookie
  3. 可能被用户禁用, 导致功能无法使用