前言
这篇文章实话说我有点虚,因为平时都不怎么研究这一块的,然后涉及到的知识点超多,我只能到处看看资料总结一下相关信息,所以在此我只想说句:
本文章内容只代表个人立场,有错必改!
原本打算一次性总结,后来越扯越多超过字数限制了,就干脆做成http系列文章了,不定时更新原有内容(发现哪里出错的话),不定时新增系列文章,请见谅!
因为之前写得太臃肿又不够详细,最近刚好复习到这一块的内容,所以决定把这些文章都拆分成更加细致一点,补充详细内容,优化排版布局,目前来看还是应该的,因为自身时间问题和平台编译的问题迟迟未改,只好等都改完之后才发出来。
网络协议系列 — TCP、UDP、SOCKET与参考模型
缓存机制
读到这里大家应该也知道每次http请求要经过多少步骤涉及多少知识点了,在实际项目中请求往往是有相当数量的,但是其中有些请求是重复多余的,而这一节要讲的缓存就是为了这些请求而存在,http缓存机制在性能优化这一块尤为重要:
- 避免不必要的数据传输甚至不需要发送请求;
- 降低网络状况和距离时延影响,因为上一条;
- 减少服务器的压力,因为上两条;
总体流程如下
当浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强制缓存:
- 如果命中,浏览器直接从自己的缓存中读取资源,流程结束;
- 如果没有命中,浏览器一定会发送一个请求到服务器;
服务器端收到请求之后依据资源的另外一些http header验证这个资源是否命中协商缓存:
- 如果命中,服务器会返回对应状态码,但是不会返回这个资源的数据,而是让客户端直接从缓存中加载这个资源,流程结束;
- 如果没有命中,浏览器直接从服务器加载最新资源数据,流程结束;
Pragma(已废弃)
pragma
是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求-响应”链中可能会有不同的效果。它用来向后兼容只支持 HTTP/1.0 协议的缓存服务器,那时候 HTTP/1.1 协议中的 Cache-Control 还没有出来。
客户端不对该资源读取缓存,即每次都得向服务器发一次请求才行。Pragma属于通用首部字段,在客户端上使用时,常规要求我们往html上加上这段meta元标签(仅对该页面有效,对页面上的资源无效),优先级高于Cache-Control:
<meta http-equiv="Pragma" content="no-cache">
缺点:
由于 Pragma 在 HTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。
强制缓存
Expires
指定了一个日期/时间,必须是格林威治时间(GMT),在这个日期/时间之后,HTTP响应被认为是过时的;无效的日期,比如 0,代表著一个过去的事件,即该资源已经过期了。
缺点:
- 时间是由服务器发送的,和客户端时间不一定一致,无法用于精确度高的需求;
- 如果同时设置了 "max-age" 或者 "s-max-age" 指令的Cache-Control响应头,那么Expires头就会被忽略;
- 过期之前即使资源修改了也依旧使用旧资源,非即时性缓存,强制缓存通病;
Cache-Control
在http请求和响应中通过指定指令来实现缓存机制。缓存指令是单向的,这意味著在请求设置的指令,在响应中不一定包含相同的指令。
优点:
- 以时间间隔标识失效时间,避免服务器和客户端相对时间的问题;
- 灵活的自定义配置选项;
缺点:
- HTTP 1.1 才有的内容,不适用于HTTP 1.0;
- 过期之前即使资源修改了也依旧使用旧资源,非即时性缓存,强制缓存通病;
可缓存性
字段名 | 描述 |
---|---|
public | 表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存。 |
private | 表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。 |
no-cache | 告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验 |
only-if-cached | 表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝 |
到期
字段名 | 描述 |
---|---|
max-age=秒 | 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。如果和Last-Modified一起使用时,优先级较高 |
s-maxage=秒 | 覆盖max-age 或者 Expires 头,但是仅适用于共享缓存(比如各个代理),并且私有缓存中它被忽略。 |
max-stale(=<秒>) | 表明客户端愿意接收一个已经过期的资源。可选的设置一个时间(单位秒),表示响应不能超过的过时时间。 |
min-fresh=秒 | 表示客户端希望在指定的时间内获取最新的响应。 |
重新验证加载
字段名 | 描述 |
---|---|
must-revalidate | 告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验 |
proxy-revalidate | 与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。 |
immutable | 表示响应正文不会随时间而改变。资源(如果未过期)在服务器上不发生改变,因此客户端不应发送重新验证请求头(例如If-None-Match或If-Modified-Since)来检查更新,即使用户显式地刷新页面。在Firefox中,immutable只能被用在 https:// transactions。 |
其他
字段名 | 描述 |
---|---|
no-store | 缓存不应存储有关客户端请求或服务器响应的任何内容。 |
no-transform | 不得对资源进行转换或转变。Content-Encoding,Content-Range,Content-Type等HTTP头不能由代理修改。例如,非透明代理可以对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。no-transform指令不允许这样做。 |
例如缓存静态资源可以这么设置
Cache-Control:public,max-age=302460601000
交互
动作 | 结论 |
---|---|
打开新窗口 | 如果指定cache-control的值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:Cache-control: max-age=5 表示当访问此网页后的5秒内不会去再次访问服务器。 |
在地址栏回车 | 如果值为private或must-revalidate,则只有第一次访问时会访问服务器,以后就不再访问。如果值为no-cache,那么每次都会访问。如果值为max-age,则在过期之前不会重复访问。 |
按后退按扭 | 如果值为private、must-revalidate、max-age,则不会重访问,而如果为no-cache,则每次都重复访问。 |
按刷新按扭 | 无论为何值,都会重复访问。 |
协商缓存
Last-Modified && If-Modified-Since
服务器在响应请求时,告诉浏览器资源的最后修改时间Last-Modified。之后客户再次请求时可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。
优点:
- 如果资源修改了服务器就会返回最新资源;
- 如果资源没修改服务器就只返回304(Not Modified)状态码,节省不必要的数据传输;
缺点:
- 文档的最后改动不意味著实际内容有改动,这时候的缓存是不起作用了;
- If-Modified-Since能检查到的粒度是s级的,无法识别一秒内进行多次修改的情况;
- 某些服务器不能精确的得到文件的最后修改时间;
- 一定会发送请求,协商缓存通病;
ETag && If-None-Match
ETag一般不以明文形式相应给客户端。在资源的各个生命周期中,它都具有不同的值,用于标识出资源的状态。当资源发生变更时,如果其头信息中一个或者多个发生变化,或者消息实体发生变化,那么ETag也随之发生变化。Etag由服务器端生成,客户端通过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改。
优点:
- Etag是根据资源内容计算出来的,比单纯比较资源最后修改时间的做法精确度高得多;
- 能识别一秒内进行多次修改的情况;
- Etag可以综合Inode,MTime和Size避免某些服务器不能精确的得到文件的最后修改时间这个问题;
缺点:
- 分布式服务器存储的情况下,计算ETag的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时发现ETag不匹配的情况;
- ETag不管怎么样的算法,在服务器端都要进行计算,计算就有开销,会带来性能损失;
- 一定会发送请求,协商缓存通病;
总结流程图
因为Cache-Control自定义配置效果太多,就一笔带过了,大家知道就好。
浏览器缓存文件
浏览器为了提高性能,一般会在脚本,图片等文件解析执行之后直接存进内存缓存中,刷新页面的时候直接读取出来(from memory cache),css文件会存进硬盘文件中,所以每次渲染页面都需要从硬盘读取(from disk cache)。
- 内存缓存: 快速读取,进程关闭清空
- 硬盘缓存: 需要对硬盘文件进行I/O操作,然后重新解析内容,读取相对复杂缓慢
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。