一条URL从浏览器地址栏开启的奇妙之旅

350 阅读3分钟

足迹

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

阶段

这些足迹可以归纳为以下五个阶段:

  1. 浏览器强缓存检查阶段。足迹1-2
  2. 浏览器与服务器建立TCP连接阶段。足迹3-7
  3. 缓存协商阶段。足迹8-9
  4. 服务器响应阶段。足迹10-11
  5. 浏览器处理响应阶段。足迹12-17

足迹图

足迹图

原文 一条URL从浏览器地址栏开启的奇妙之旅

我的主页

我的github

我的微博:九毫