足迹
- 在浏览器地址栏输入 URL
- 检查缓存,此时缓存为强缓存
- 不存在缓存,发起新请求
- 存在缓存,检查缓存是否新鲜,新鲜使用浏览器缓存(状态码为200(from cache)、from disk cache(磁盘缓存)和from memory cache(内存缓存)),不新鲜则进行服务器验证
- 强缓存是通过两个http头进行控制,Expires和Cache-control
- Expires在http 1.0中提供,用一个绝对时间表示缓存新鲜时间,受本地时间影响。
- Cache-Control在http 1.1中新增,Cache-Control: max-age=,的值以秒为单位,表示相对过期时间。
- Cache-Control优先级要高于Expires。
- 强缓存没有命中,浏览器解析URL,获取协议、主机、端口、path。
- 浏览器封装请求报文
- 浏览器获取主机ip,获取主机ip方式如下:
- 浏览器缓存
- 本机缓存
- host文件
- 路由器缓存
- ISP DNS缓存
- DNS递归查询(可能存在负载均衡导致每次 IP 不一样)
- 打开socket与目标ip地址建立TCP连接,进行三次握手。
- 客户端发送一个 TCP 的SYN=1,Seq=X的包到服务器端口
- 服务器发回SYN=1, ACK=X+1, Seq=Y的响应包
- 客户端发送ACK=Y+1, Seq=Z
- 建立连接之后,发送HTTP请求
- 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用 HTTP Host 头部判断请求的服务程序
- 协商缓存,判断请求头是否存在ETag/If-None-Match,存在判断是否新鲜,资源新鲜,即:未变更,则返回304状态,浏览器使用本地缓存。否则判断是存在Last-Modified/if-modified-since,如果存在则判断是否新鲜,新鲜则返回304状态,浏览器使用本地缓存。ETag的优先级比Last-Modified更高,使用ETag主要是基于以下几点:
- 有些文件会同期性更改,但是内容并没有变更(仅仅是修改时间有变化 ),这时并不希望客户端认为这个文件变更,而重新GET请求
- 某文件修改比较频繁,1秒内修改多次,由于Last-Modified是秒级的,所以无法判断这种情况
- 某些服务器不能精确的得到文件的最后修改时间
- 如果ETag判断不新鲜、Last-Modefied不新鲜或者请求头中ETag和Last-Modified都不存在的情况下,处理程序读取完整请求并准备 HTTP 响应,可能需要查询数据库等操作
- 服务器将响应报文通过 TCP 连接发送回浏览器
- 浏览器接收HTTP响应,依据情况选择关闭TCP连接或者保留重用。关闭TCP连接4次挥手如下:
- 主动方发送Fin=1, Ack=Z, Seq= X报文
- 被动方发送ACK=X+1, Seq=Z报文
- 被动方发送Fin=1, ACK=X, Seq=Y报文
- 主动方发送ACK=Y, Seq=X报文
- 浏览器判断响应状态码,对1xx、3xx、4xx、5xx状态处理。
- 处理2xx状态的响应
- 判断是否可缓存,如果可以缓存进行缓存
- 浏览器对资源进行解码,如Gzip
- 浏览器对不同类型的资源进行相应的处理,HTML文件会进行HTML解析,从此又开启了一段HTML解析之旅……
阶段
这些足迹可以归纳为以下五个阶段:
- 浏览器强缓存检查阶段。足迹1-2
- 浏览器与服务器建立TCP连接阶段。足迹3-7
- 缓存协商阶段。足迹8-9
- 服务器响应阶段。足迹10-11
- 浏览器处理响应阶段。足迹12-17
足迹图

我的微博:九毫