Cookie、Session、LocalStorage、Cache-Control

Cookie


定义

Cookie(复数形态Cookies),中文名称为“小型文本文件”或“小甜饼[1],指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。由网景公司的前雇员卢·蒙特利在1993年3月发明[2]。最初定义于RFC 2109。目前使用最广泛的 Cookie标准却不是RFC中定义的任何一个,而是在网景公司制定的标准上进行扩展后的产物。

分类

Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie。

内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失,硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。

用途

因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。

比如购物网站, 由于http是无状态的, 所以如果不采用其他手段. 服务器根本不知道用户到底买了什么, 购物车里到底保存了什么,

在刚才的购物场景中,当用户选购了第一项商品,服务器在向用户发送网页的同时,还发送了一段Cookie,记录着那项商品的信息。当用户访问另一个页面,浏览器会把Cookie发送给服务器,于是服务器知道他之前选购了什么。用户继续选购饮料,服务器就在原来那段Cookie里追加新的商品信息。结帐时,服务器读取发送来的Cookie就行了。

特点

  1. 服务器通过 Set-Cookie 响应头设置 Cookie
  2. 浏览器得到 Cookie 之后, 每次请求都要带上 Cookie
  3. 服务器读取 Cookie 就知道登陆用户的信息
  4. Cookie 可以在开发者工具的 application 中修改
  5. Cookie 有效期默认20分钟左右
  6. 后端可以强制设置有效期

过程图

我们以登陆界面为例

登陆


session


  1. 将 SessionID(随机数)通过 Cookie 发送给客户端
  2. 客户端访问服务器时, 服务器读取 SessionID
  3. 服务器有一块内存(哈希表)保存了所有 session
  4. 通过 SessionID 我们可以得到对应用户的隐私信息, 如 id 等
  5. 这块内存(哈希表)就是服务器上的所有 session


localStorage


html5提供的一个API, 在浏览器建立一个哈希表用来存储内容, 只接受字符串

使用

localStorage干什么用?
我们都知道, 假设我们在js里面声明了一个变量, 并给变量赋值, 当我们关闭或者刷新页面后, 之前声明的变量就销毁了, 没有办法永久保存, 当我们想要在关闭或刷新页面后, 持久化保留某个变量和它的值的时候, 就可以利用localStorage来保存它。


localStorage

假设我们有以下场景

  1. 第一次登陆网页提示网站改版
  2. 之后再登陆不提示

我们就可以用 localStorage 实现

let already = localStorage.getItem('alreadyAlert')
if(!already) {
  alert('你好, 我们网站改版了, 有了这些新功能.....')
  localStorage.setItem('alreadyAlert', true)
}

特点

  1. localStorage 跟 HTTP 无关
  2. HTTP 不会带上 localStorage 的值
  3. 只有相同域名的页面才能互相读取 localStorage
  4. 每个域名 localStorage 最大存储量为 5Mb 左右
  5. 常用场景: 记录有没有提示过用户等功能(没有用的信息, 不能记录密码)
  6. localStorage 永久有效, 除非用户清理缓存

SessionStorage

1、2、3、4同上

  1. SessionStorage 在用户关闭页面后就失效
  2. 用法也同localStorage


Cache-Control(缓存控制)


缓存

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经在本地存储,它就会拦截请求,返回保存的资源,而不会去源服务器重新下载。

缓存可以缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要手段之一。缓存需要合理配置,因为并不是所有资源都是永久不变的:重要的是对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。

缓存种类

缓存的种类有很多,其大致可归为两类:私有缓存共享缓存
共享缓存存储的响应能够被多个用户使用。私有缓存只能用于单独用户。
我们主要介绍浏览器与代理缓存
[站外图片上传中...(image-612554-1524639617439)]


(私有)浏览器缓存

私有缓存只能用于单独用户。你可能已经见过浏览器设置中的“缓存”选项。浏览器缓存拥有用户通过 HTTP 下载的所有文档。这些缓存为浏览过的文档提供向后/向前导航,保存网页,查看源码等功能,可以避免再次向服务器发起多余的请求。它同样可以提供缓存内容的离线浏览。

(共享)代理缓存

共享缓存可以被多个用户使用。例如,ISP 或你所在的公司可能会架设一个 web 代理来作为本地网络基础的一部分提供给用户。这样热门的资源就会被重复使用,减少网络拥堵与延迟。

缓存控制

Cache-control 头

HTTP/1.1定义的 Cache-Control 头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。

禁止进行缓存

缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。

Cache-Control: no-store
Cache-Control: no-cache, no-store, must-revalidate

强制确认缓存

如下头部定义,此方式下,每次有请求发出时,缓存会将此请求发到服务器(该请求应该会带有与本地缓存相关的验证字段),服务器端会验证请求中所描述的缓存是否过期,若未过期(实际就是返回304),则缓存才使用本地缓存副本。

Cache-Control: no-cache

私有缓存和公共缓存

"public" 指令表示该响应可以被任何中间人(比如中间代理、CDN等)缓存。若指定了"public",则一些通常不被中间人缓存的页面(因为默认是private)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定影响状态码的页面),将会被其缓存。

而 "private" 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。

Cache-Control: private
Cache-Control: public

缓存过期机制

过期机制中,最重要的指令是 "max-age=<seconds>",表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。

Cache-Control: max-age=31536000

缓存验证确认

当使用了 "must-revalidate" 指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。详情看下文关于缓存校验的内容。

Cache-Control: must-revalidate

新鲜度

理论上来讲,当一个资源被缓存存储后,该资源应该可以被永久存储在缓存中。由于缓存只有有限的空间用于存储资源副本,所以缓存会定期地将一些副本删除,这个过程叫做缓存驱逐。另一方面,当服务器上面的资源进行了更新,那么缓存中的对应资源也应该被更新,由于HTTP是C/S模式的协议,服务器更新一个资源时,不可能直接通知客户端及其缓存,所以双方必须为该资源约定一个过期时间,在该过期时间之前,该资源(缓存副本)就是新鲜的,当过了过期时间后,该资源(缓存副本)则变为陈旧的驱逐算法用于将陈旧的资源(缓存副本)替换为新鲜的,注意,一个陈旧的资源(缓存副本)是不会直接被清除或忽略的,当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源(缓存副本),则缓存会先将此请求附加一个If-None-Match头,然后发给目标服务器,以此来检查该资源副本是否是依然还是算新鲜的,若服务器返回了 304 (Not Modified)(该响应不会有带有实体信息),则表示此资源副本是新鲜的,这样一来,可以节省一些带宽。若服务器通过 If-None-MatchIf-Modified-Since 判断后发现已过期,那么会带有该资源的实体内容返回。

下面是上述缓存处理过程的一个图示:

[站外图片上传中...(image-ea0fc1-1524639617440)]

对于含有特定头信息的请求,会去计算缓存寿命。比如Cache-control: max-age=N的请求头,相应的缓存的寿命就是N。通常情况下,对于不含这个属性的请求则会去查看是否包含Expires属性,通过比较Expires的值和头里面Date属性的值来判断是否缓存还有效。如果max-age和expires属性都没有,找找头里的Last-Modified信息。如果有,缓存的寿命就等于头里面Date的值减去Last-Modified的值除以10(注:根据rfc2626其实也就是乘以10%)。

缓存失效时间计算公式如下:

expirationTime = responseTime + freshnessLifetime - currentAge

上式中,responseTime 表示浏览器接收到此响应的那个时间点。

缓存更新

通常我们对于css文件和js文件的max-age都设置1年以上, 但是如果这期间文件更新了怎么办呢?

只有url相同才会调用缓存, 所以当有文件更新时候, 对文件名加入随机数或者MD5值使文件路由地址不一样就可以了, 比如我们刚开始的文件

<link rel="stylesheet"  href="/style.css">

若文件更新了, 我们让文件名变成

<link rel="stylesheet"  href="/style125445.css">

这样引用文件的路由就变了, 这样就不会使用之前的缓存了

下面的截图是百度的请求, css请求和js请求后面的那些不规则数字就是利用我们这种方法实现缓存更新的


缓存更新

Expires(不常用)

在Cache-Control出来之前我们用Expires, 现在用的不多了, 这里就大概提一下, 比如在node中, 我们跟设置其他响应头一样, 在响应头中设置Expire时间, 到了那个时间缓存就会过期, 这个时间需要用GMT时间, 但是这有个缺点, 这个时间是根据机器的本地时间来判断的

response.setHeader('Expires', 'Sun, 04 Feb 2018 14:3:05 GMT')

Etag

MD5
信息摘要算法, 用于校验文件内容是否相同, 相同内容的文件MD5值相等, 内容差异越小, MD5值差异越大。
通常我们在下载电影或者安装包等文件的时候经常会用到MD5校验, 用来校验我们下载的文件是不是跟目标文件一样。
所以, 对于js文件或者css文件, 我们同样可以用MD5来判断文件是否相同, 假设我们在nodejs中已经引用了MD5包, 并算出了js文件的MD5值, 我们设置Etag并赋值为js文件的MD5值

response.setHeader('ETag',  fileMD5)

当我们在响应头中设置ETag后, 在下次请求过来时, 请求头就会带有一个if-none-match, 它的值就是上次响应头中的ETag值, 这样我们就可以在后端检验这个值, 如果这个值跟这次响应中的ETag值不相等, 就更新文件

response.setHeader('ETag', fileMD5)
if(request.headers['if-none-match'] === fileMD5) {
  response.statusCode = 304
  //不用返回响应体
}else {
  // 返回新版js文件
  response.write(newJsFile)
  response.end()
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容