Percy

深入理解cookie在http请求中的工作方式

首先回顾下cookie和session的工作方式.

session id是B/S架构中, 用来维持会话状态的通信密匙,在PHP的配置中这个密匙默认的名字是: PHPSESSID, 当然你可以根据自己的喜好改成你喜欢的名字, 例如百度改成了BIDUPSID,

以百度https://www.baidu.com/ 为例, 用户第一次访问www.baidu.com的时候,

由于请求头(Request Header)的cookie中没有带BIDUPSID, 百度的服务器就会认为这是一个新的会话,

会在服务端给这次会话生成一个唯一标识的session id, (如果具体在PHP代码里,就是session_start()这个函数),同时会在http请求的Response Header 中将这个session id带给浏览器.(这其实是在告诉浏览器,你保存好这个密匙, 下次你来找我的时候,请带上这个钥匙, 这样我就还认识你.) 反应在请求的response header里,就是下面这行:

1
Set-Cookie:BIDUPSID=D5C1249DB29F3D68F9D36E64210; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com

这个session id就是key=BIDUPSID, value=D5C1249DB59C429F3D68F9D36E642E90这样一个结构, (此时,在百度的服务器端会生成以value命名的一个文件,用于记录这个用户的访问信息.)

此时http请求response之后, 浏览器请求接收到response中的Set-Cookie命令之后,就会在浏览器中设置cookie值BIDUPSID=D5C1249DB59C429F3D68F9D36E642E90, 并在以后请求*.baidu.com这类域名时都带上这个cookie值, 即Request Header中带上

1
cookie: BIDUPSID=D5C1249DB59C429F3D68F9D36E642E90

这样服务器就可以通过这个密匙来辨别请求来自哪个用户, 应用到实际中, 即可以作为记住登录状态之用.

如何操作cookie

  1. 如何删除cookie?

    首先明确, Server(服务器)和client(浏览器)都可以操作cookie

    • Server端删除cookie. cookie存在于客户端, server端是无法直接对cookie值进行删除的. 服务器端删除cookie, 可以通过如下的函数设置. 实现原理是通过在请求的返回头中设置cookie的过期时间来达到让浏览器清除cookie的效果.

      1
      setcookie("user_id","", time()-86400*7, "/", '.domain.com');

      这个函数,会让http请求的返回头中带上

      1
      Set-Cookie:user_id=111112222; expires=Wed, 01-Mar-2017 08:50:52 GMT; Max-Age=-604800; path=/; domain=.ganji.com

      这样这样一个参数, 表示的就是让浏览器设置user_id这个cookie过期.

    • 浏览器端删除cookie就简单了,直接用JavaScript操作cookie过期即可 .
  2. cookie的正确使用姿势?
    • 在每次http请求中, 存储在cookie中的数据都被带上, 因此什么都往cookie存的话,无疑增加了网络开销. 所以在cookie之后又出现了localstorage专门用于存储. 而cookie则是用于存放服务端和客户端交互用到的数据, 例如session id这类身份认证等信息, 可以减少每次重复认证的操作, 是应该放在cookie里. 但是一些不是每次都需要发送给服务器的数据, 就不应该放在cookie里, 而是放在localstorage里. 当然在localstorage出现之前, cookie一度被滥用, 当做浏览器存储信息的工具了
  3. 生产环境中如何合理的生成cookie?

    • 生成cookie可以在浏览器也可以在服务器生成. 什么样的方式才是正确的呢
      这个得看使用场景来决定, 例如PHPSESSION这类密匙性质的cookie, 是应该在服务端生成. 一些其它的值, 例如某网站需要生成一个唯一标示用户的字符串又不涉及到安全的,这种则可以放在客户端利用JavaScript代码生成的, 这样可以节省请求中的网络消耗