Cookie & 浏览器Header缓存设置

前言

由于HTTP无状态协议,有时需要保存资源状态信息或者用户信息,根据状态判断是否需要重新请求资源或者在相同域名和端口下读取用户信息。

缓存可以使浏览器重用已获取的资源和保存用户信息,优化静态资源的加载速度以及加速页面的渲染速度。

缓存包括很多方面,这里仅简要介绍下数据缓存Cookie及相关设置和浏览器header缓存匹配策略(ETag, Cache-Control)

缓存分类.png
Cookie

一般Cookie是由首次请求时, 服务器在HTTP的响应头通过Set-Cookie给客户端的一串字符串及metadata,比如用户信息或资源状态信息或对缓存的控制信息等,浏览器收到响应后,会将Cookie保存在客户端一段时间,然后客户端每次访问的相同域名的网页时,浏览器会按照一定的原则(浏览器缓存策略)将Cookie发送给服务器。

Cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围

  == Server -> User Agent ==

  Set-Cookie:SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
  Set-Cookie: lang=en-US; Path=/; Domain=example.com
  Set-Cookie: Expires=Wed, 09 Jun 2021 10:18:14 GMT
##path:/设置浏览器即UA下一次请求每个路径都带上缓存
##Domain: example.com每个example.com下的子域名都带上缓存
   == User Agent -> Server ==

Cookie: SID=31d4d96e407aad42; lang=en-US

注意

  1. 客户端可以对Cookie进行修改,通过控制台或者Javascript脚本。
  2. Cookie默认在用户关闭页面后就失效(保存在内存中),服务器可以通过cache-control设置强缓存-Cookie缓存位置及时间等(保存在硬盘中)。
  3. 可通过Set cookie指定expires为过去的一个值,使指定路径的Cookie失效。
  4. Cookie大小在4k左右, 域名、端口相同即可共享(CSRF)
  5. 可通过document.cookie获取cookie信息
  • Session
    考虑到客户端可以对cookie中的用户信息等进行修改,为了提高安全性,首次请求时服务器仅将一个随机数生成的的SessionID通过Set-Cookie发送给客户端,而具体的哈希表则保存在服务器,即用户的状态信息等保存在服务端的内存中,客户端再次请求时,仅通过SessionID获取其对应的信息,服务器通过读取相应的SessionID返回对应用户的隐私信息。
##首次请求响应
HTTP/1.1 200 OK
Date: Sun, 17 Sep 2017 13:16:06 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache
Pragma: no-cache
Set-Cookie: SESSIONid=v666iuanetgmcv0couvmnf3jg4
Content-Length: 20
Content-Type: text/html
##接下来的请求
GET /clients/ HTTP/1.1
Host: mycompany.com
Accept: text/html
Cookie: SESSIONid=v666iuanetgmcv0couvmnf3jg4 
  • Cookie & Session 区别
    1. Cookie保存在客户端浏览器中,而Session保存在服务器上
    2. Cookie可以设置路径path及domain属性值,使不同路径,不同二级域名下共享。

浏览器Header缓存策略
  1. 浏览器在加载资源时,根据请求头的expires和cache-control判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器。
  2. 如果没有命中强缓存,浏览器发送一个请求到服务器,通过last-modified或etag验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取资源
  3. 如果前面两者都没有命中,直接从服务器加载资源
  • Cache-Control--强缓存
    Cache-Control是HTTP/1.1中引入的Header设置,用于控制网页缓存。它有如下的选项:
    1、public : 客户端和代理服务器(CDN)都可缓存
    2、private : 只在客户端缓存,cache-control的默认值
    3、no-cache: 不论是客户端缓存还是服务器缓存,在使用它以前必须用缓存里的值来重新验证
    4、no-store: 不允许被缓存
    5、max-age=<seconds> : 设置缓存时间
    6、s-maxage=<seconds>:覆盖 max-age 属性。只在共享缓存中起作用。
    7、immutable:表示文档是不能更改的。
    8、must-revalidate:表示客户端(浏览器)必须检查代理服务器上是否存在,即使它已经本地缓存了也要检查。
    9、proxy-revalidata:表示共享缓存(CDN)必须要检查源是否存在,即使已经有缓存。
    流程图如下:
    Cache-Control.png

早期HTTP /1.0中则通过服务器在Header中Set-Cookie设置Expires来实现缓存控制,表示资源到什么时候过期(绝对时间),一旦修改本地时间,可能造成缓存失效。

  • ETag及二次验证--协商缓存
    ETag也是设置在Header中,HTTP /1.1引入,用于缓存控制,但其值是内容的MD5值以及其他诸如文档版本/日期等的信息。
    ETag的使用通常是首次请求服务器时,服务器返回包含Last-Modified及ETag字段的响应头,若客户端在很短时间再次访问相同的域名,浏览器将仅发送一个包含If-None-Match:MD5(之前响应的MD5值) ,若内容发生变化,服务器将返回一个新的响应,否则则返回一个HTTP 304响应头。
    E-Tag.png
##Request
GET /hello.txt HTTP/1.1
If-None-Match: "8a75d48aaf3e72648a4e3747b713d730"
Host: www.foobar.tld

##Response
HTTP/1.1 304 Not Modified
Date: Sun, 05 Feb 2017 12:34:57 UTC
Server: Apache
Last-Modified: Sun, 05 Feb 2017 10:34:56 UTC
ETag: "8a75d48aaf3e72648a4e3747b713d730"
Content-Length: 8
Content-Type: text/plain; charset=UTF-8

早期HTTP /1.0使用首次响应返回Last-Modified,接下来请求头加上If-Modified-Since来实现协商缓存,相比ETag基于内容是否变更,其是否刷新缓存是通过修改时间是否变更来判断。有以下缺点:

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
  • 某些服务器不能精确的得到文件的最后修改时间。

若两者同时使用,则ETag优先级比Last Modified要高

  • 浏览器缓存
    浏览器发送请求时首先判断是否是强缓存,查看缓存信息,判断缓存状态,然后看是否需要进行协商缓存。而目前大部分web服务器都默认开启协商缓存,而且是同时启用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】
    1. Cache-Control —— 请求服务器之前
    2. Expires —— 请求服务器之前
    3. If-None-Match (Etag) —— 请求服务器
    4. If-Modified-Since (Last-Modified) —— 请求服务器

注意:

  1. 分布式系统里多台机器间文件的Last-Modified必须保持一致,以免负载均衡到不同机器导致比对失败;
  2. 分布式系统尽量关闭掉ETag(每台机器生成的ETag都会不一样);

其他:
  • URL重写:
    通过设置cookie保存时间可使浏览器只读缓存中的内容而不重新发送请求,但有时需要强制更新cookie,可通过URL重写把SessionID+版本号附加到URL路径的后面。浏览器发现URL发送变化后将自动发送请求。
  • 常见Set-Cookie配置信息
key value
expires Cookie失效时间(绝对时间)若不设置,浏览器关闭即删除
Max-Age Cookie失效时间,相对时间,优先级高于expires
path 设置哪些路径带上cookie,一般默认为'/'
Domain 设置哪些域名带上cookie,一般为当前一级域名
Secure 只在https下才能发送cookie
HttpOnly js脚本获取不到,且只能在http上才能发送cookie(防止xss)
SameSite 是否可能作为第三方 cookie(防止CSRF)
  • 常见响应头信息
key value
pragma http1.0, 值为no-cache为禁用缓存
vary 基于字段区分缓存版本(res header)
Date 发送响应报文的时间(协商缓存、代理服务器缓存)
Age 文件存于服务器的时间
accept-encoding 请求服务器返回的文件类型
referrer 发送请求的源域名
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343