Web开发须知的浏览器内幕 缓存与存储篇(2)
本文禁止转载,由UC浏览器内部出品。
3. HTTP Cache
综述
HTTP Cache是完全按照IETF规范实现的,最新的RFC规范地址是
https://tools.ietf.org/html/rfc7234。它的作用就是保存可缓存的响应以备重新使用,在下次请求时可减少响应时间和网络带宽。只有GET和HEAD method会缓存。
浏览器的优化
浏览器是过滤了部分没有意义进行缓存的响应头才保存到磁盘,例如Connection(keep-alive)、www-authenticate等。这能减少耗时较多的磁盘IO时间。另外Cookie也不会保存在HTTP Cache,而是存到专门的Cookie Storage。
新的规范允许先使用后验证(stale-while-revalidate)https://tools.ietf.org/html/rfc5861
在隐身模式下,不存在磁盘读写的HTTP Cache。
http://www.chromium.org/user-experience/incognito。
但是某些浏览器厂商可能做优化,在临时文件夹中读写,退出或重启即删。
容量
容量是以整体计算的,不区分Domain。
Android WebView是20MB。iOS WebView也可能是20MB(根据https://github.com/gnustep/base/blob/master/Source/NSURLCache.m,不确定GNUstep是否也是Apple的源码)。
PC上的Chromium是以80MB为基准结合磁盘可用空间来考虑的,最大是320MB。算法是:
// js伪代码
if (可用空间 < 100MB)
容量 = 80%的可用空间 // < 80MB
else if (可用空间 < 800MB)
容量 = 80MB
else if (可用空间 < 2000MB) // 约2GB
容量 = 10%的可用空间 // < 200MB
else if (可用空间 < 20000MB) // 约20GB
容量 = 200MB
else // >= 20000MB
容量 = Math.min(1%的可用空间, 320MB) // 200MB <= 容量 <= 320MB
其它基于Chromium开发的浏览器可能会修改这个算法,特别是移动浏览器会扩大那个常量值,以更高容量来提高资源复用数(嗯,不是复用率)。
淘汰
淘汰算法是一般是LRU,但在一些场景会结合文件大小、时间因素等做进一步优化。Cache的管理模块会记录总的缓存大小,每次创建新的缓存时会判断是否缓存是否超出容量限制,满了就会按LRU淘汰一定比例的缓存。
浏览器需要对缓存的文件进行索引,如果这个索引损坏,浏览器会删除所有的缓存。用户也可以通过设置界面来删除。此外,第三方程序也会做清理。
Revalidation
用户点击刷新按钮,会强制走revalidate流程,其它的情况都按照规范来执行。
RFC规范不只是为服务器和浏览器设计的,还考虑了网络中的各种节点,比如代理服务器、CDN服务器、智能路由等。
Chromium肯定是严格遵守RFC规范的,但第三方浏览器通常会破坏这些规范来获得一定的性能提升。比如更宽松的缓存条件。
Chromium代码参考:http_response_headers.cc : RequiresValidation
后端优化
后端需要在响应中添加Cache-Control来利用浏览器缓存。
- Expires不要超过一年。
- 稳定的文件应该加上max-age。max-age不要大于2^31,以免大于int32而变成负数。
- Some HTTP/1.0 caches might not implement Cache-Control.对HTTP 1.0可以使用Pragma
没有任何与过期相关的指令的话,是由client端决定是否缓存的。Chromium有缓存,但再次请求的时候并不会走Revalidate流程,还是会得到200 OK。
因为HTTP Cache以URL为key,所以不想用以前的缓存,则可以更换URL,例如加不同的query、改文件名(如加上MD5或版本号)等。URL是忽略锚点的。
要做性能优化的同学,可以在协议文档里淘金。鉴于网上也有不少文章,这里不做整理了。
4. Cookie Storage
综述
因为Cookie是在多个请求头中复用数据的,所以需要从响应头中抽取出来另外保存。而且Cookie有自己的生命周期管理语法,就有独立的模块来管理。Cookie数据同时保存在内存和磁盘。
容量
容量是规范里就有建议最小值的。最新规范是RFC6265,它引用两个比较旧的规范RFC2965和RFC2109。
其中最老的规范RFC2109的6.3.1节中就有说明:
拒绝服务攻击
浏览器应该按照host或域名设置Cookie的数量和数据大小上限。
Denial of Service Attacks
User agents may choose to set an upper bound on the number of cookies
to be stored from a given host or domain name or on the size of the
cookie information. Otherwise a malicious server could attempt to
flood a user agent with many cookies, or large cookies, on successive
responses, which would force out cookies the user agent had received
from other servers. However, the minima specified above should still
be supported.
Chromium的实现是:
- 每个Cookie的最大长度为4096 bytes。大于这个长度的Cookie将不被处理,即不会保存。
- 每个域的最大数量是180个
- 总体的个数是3300个
这里有各个浏览器的Cookie限制列表:http://browsercookielimits.squawky.net/。
内存缓存
从容量可知,所有Cookie占用的最大内存为3300*4K ≈ 13M。这点内存在手机上也是支撑得了的,所以Chromium会把硬盘上的全部Cookie数据都读到内存,每次发送请求都是在内存中查找,所以速度很快。在收到响应,需要创建或更新Cookie时,Chromium才会去写硬盘。而这个写操作是在非网络线程中完成的,避免慢速的文件IO占用网络线程的时间。
内存中的组织是以eTLD+1为key放在multimap里。
Chromium用SQLite存放cookie。在PC上是对value加密的。在iOS不加密,因为它的沙箱机制足够完善了,除非越狱。
Chromium把增删改表示为操作,向数据库发指令,而不是全部写一次。它是在后台线程flush。每30秒或满512次操作就直接Flush。
参考
http://www.quantum-step.com/download/sources/mystep/Foundation/Sources/NSHTTPCookieStorage.m
Apple是用了系统的NSHTTPCookieStorage。是全写的。
(注:本节的描述经过简化,非真实完整的实现)
淘汰
每次创建或更新Cookie就会进行垃圾回收的判断。有下列的规则:
1. 先淘汰过期的。即超出Max-Age指定时间。
2. 如果超出容量,则会按LRU规则(这里的used是指accessed)淘汰掉300个Cookie。
3. 如果最近30天内有访问过,即使超出容量也不会淘汰掉。
下面是Chromium源码中的部分注释供参考。
// Any cookies accessed more recently than kSafeFromGlobalPurgeDays will not
// be evicted by global garbage collection, even if we have more than
// kMaxCookies. This does not affect domain garbage collection.
const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
const size_t CookieMonster::kPurgeCookies = 300;
const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
const size_t CookieMonster::kDomainCookiesQuotaHigh =
kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
kDomainCookiesQuotaMedium;
开发建议
- 浏览器可能会被用户设置成禁用Cookie。当确实需要Cookie而发现获取不了时,请做好一定的提示,提升用户体验。
- 设好max-age,不要让冗余的cookie加入到请求头里,可加速连网过程。
- 因为都在内存,Cookie操作的时耗较少,但太大的cookie会在连网阶段造成较高的延时。还是乖乖地加上Expire吧。
Web开发须知的浏览器内幕 缓存与存储篇(2)的更多相关文章
- Web开发须知的浏览器内幕 缓存与存储篇(1)
本文禁止转载,由UC浏览器内部出品. 0.前言 大纲 浏览器缓存和存储相关的功能分为四类: 加载流程 Memory Cache Application Cache(简称AppCache) HTTP C ...
- Web开发基本准则-55实录-缓存策略
续上篇<Web开发基本准则-55实录-Web访问安全>. Web开发基本准则-55实录-缓存策略 郑昀 创建于2013年2月 郑昀 最后更新于2013年10月26日 提纲: Web访问安全 ...
- Atitit.h5 web webview性能提升解决方案-----fileStrore缓存离线存储+http方案
Atitit.h5 web webview性能提升解决方案-----fileStrore缓存离线存储+http方案 1. 业务场景 android+webview h5 css背景图性能提升1 2. ...
- web开发方面会遇到哪些缓存?分别如何优化
Web缓存定义: Web缓存游走于服务器和客户端之间,这个服务器可能是源服务器(资源所驻留的服务器Add),数量可能是1个或多个. Web缓存就在服务器-客户端之间搞监控,监控请求,并且把请求输出的内 ...
- Web开发须知:URL编码与解码
通常如果一样东西需要编码,说明这样东西并不适合传输.原因多种多样,如Size过大,包含隐私数据,对于Url来说,之所以要进行编码,是因为Url中有些字符会引起歧义. 例如,Url参数字符串中使用key ...
- web开发必备的浏览器常识
浏览器内核: 1.使用Trident内核的浏览器:IE.Maxthon.TT.The World等: 2.使用Gecko内核的浏览器:Netcape6及以上版本.FireFox.MozillaSuit ...
- Django中web开发用md5加密图片名并存储静态文件夹
一般在开发中,有的网站存在大量图片,首先图片的名称是不能重复的, 但是除了数据库可用的id以外我们可以用time模块中time.time()获取的时间来进行md5加密操作, 因为time模块所产生的时 ...
- web开发,关于jsp的常见问题,重复提交,防止后退。
看了网上的,有几种方法:1 在你的表单页里HEAD区加入这段代码: <META HTTP-EQUIV="pragma" CONTENT="no-cache" ...
- web开发微信文章目录
Web开发微信文章目录 2015-12-13 Web开发 本文是Web开发微信的文章目录.通过目录查看文章编号,回复文章编号就能查看文章全文. 回复编号查看全文,搜索分类名可以获得该分类下的文章. ...
随机推荐
- C#-WebForm-JS知识:基础部分、BOM部分、DOM部分、JS事件
一.基础部分: 1.JavaScript 是什么? 是一门脚本语言,是属于弱类型(语言语法很随意),C#是强类型(语言语法非常严格)(李献策lxc) 优点:JS 执行速度快 2.JS 与java有什么 ...
- Hangfire JobStorage.Current property value has not been initialized
app.UseHangfireServer() 放到 app.UseAbp() 前面 作者: zhaok 出处: http://dotnetmonkey.cnblogs.com/
- dubbo服务引用与集群容错
服务引用无非就是做了两件事 将spring的schemas标签信息转换bean,然后通过这个bean的信息,连接.订阅zookeeper节点信息创建一个invoker 将invoker的信息创建一个动 ...
- 移动端优化 && 清除移动端网站点击a标签时闪现的边框或遮罩层(CSS) && 移动端点击 && 文字不可选择
在移动端网站,当你点击加了a标签的文字或图片时,该元素的周围会闪现一个蓝色的边框,在微信上的网站就是如此:而有的浏览器会闪现一个半透明遮罩层,比如移动端的Chrome浏览器,其实这些特效无非就是为 ...
- Redis快照持久化
Redis的持久化功能: redis为了内部数据的安全考虑,会把本身的数据以文件的形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)里边. 数据保存到硬盘的过程就被称为” ...
- 深度学习(八) Batch Normalization
一:BN的解释: 定义: 顾名思义,batch normalization嘛,就是“批规范化”咯.Google在ICML文中描述的非常清晰,即在每次SGD时,通过mini-batch来对相应的act ...
- PHP之mb_internal_encoding使用
mb_internal_encoding (PHP 4 >= 4.0.6, PHP 5, PHP 7) mb_internal_encoding - Set/Get internal chara ...
- Mysql日期类型大小比较---拉取给定时间段的记录
我们知道,mysql里边,日期类型有很多表现形式,date, datetime,timestamp等类型.考虑这样一种场景: 按时间段拉取给定时间段的内容,这时,我们就得使用日期类型的比较了. 表结构 ...
- PTA (Advanced Level) 1016 Phone Bills
Phone Bills A long-distance telephone company charges its customers by the following rules: Making a ...
- 使用Vue搭建多页面应用
使用Vue-cli搭建多页面应用时对项目结构和配置的调整 前提:在这里使用的是webpack模板进行搭建 第一步.安装Vue-cli并且进行初始化 首先打开git,在里面使用npm全局安装Vue- ...