从一道经典的面试题说起
“用户输入 URL 到浏览器显示页面,这个过程发生了什么?”,作为前端开发,这个题目相信大家并不陌生。楼主的答案分为两部:
一、网络通信
-
应用层 DNS 域名解析
客户端首先将 URL 解析出主机名,然后通过域名服务将主机名转换为 IP 地址。 -
建立与服务器的 TCP 连接
三次握手:发送端先发送一个带有SYN(synchronize)标志的数据包给接收端,在一定的延迟时间内等待接收的回复。接收端收到数据包后,传回一个带有SYN/ACK标志的数据包以示传达确认信息。接收方收到后再发送一个带有ACK标志的数据包给接收端以示握手成功。在这个过程中,如果发送端在规定延迟时间内没有收到回复则默认接收方没有收到请求,而再次发送,直到收到回复为止。 -
浏览器向服务器发送一条 HTTP 请求报文
-
服务器向浏览器回送一条 HTTP 响应报文
-
关闭连接
二、页面渲染
现代浏览器渲染页面的过程是这样的:jiexiHTML以构建DOM树 –> 构建渲染树 –> 布局渲染树 –> 绘制渲染树。
而今天的主角——缓存就隐藏在这里面。
缓存的工作步骤
对于一条 HTTP GET 报文的基本缓存处理包括7个步骤。
(1)接收——缓存从网络中读取抵达的请求
(2)解析——缓存对报文进行解析,提取出 URL 和各种首部
(3)查询——缓存查看是否有本地副本,如果没有,就获取一份副本并保留在本地
(4)新鲜度检测——缓存查看已缓存副本是否足够新鲜,如果不是,就询问服务器是否有任何更新
(5)创建响应——缓存会用新的首部和已缓存的主体来构建一条响应报文
(6)发送——缓存通过网络将响应发回给客户端
(7)日志——缓存可选的创建一个日志文件条目来描述这个事物
保持副本新鲜度
缓存工作的核心,就是使用一些规则来保证缓存数据和服务器数据之间充分一致。HTTP 将这些机制称为 文档过期和服务器再验证。
文档过期
服务器用 HTTP/1.0+ 的 Expiress 首部或 HTTP/1.1 的 Cache-Control:max-age 首部来指定过期日期。
服务器再验证
用条件方法进行再验证—— If-Modified-Since 和 If-None-Match。
等等
以上提出了不少名词,但客户端和服务器之间到底是如何配合以保持缓存的新鲜度的呢?
HTTP 缓存控制对应关系:
客户端缓存控制首部 | 服务端缓存控制首部 |
---|---|
cache-control | cache-control |
expiress | date |
if-modified-since | last-modified |
if-none-match | etag |
cache-control 首部说明
Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。
请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached;
响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存
no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。