Skip to content

http 实现

浏览器作为Web客户端,负责与服务器进行 HTTP 通信,并实现高效的缓存机制。本文深入探讨浏览器如何处理 HTTP 请求和响应,以及如何利用缓存提高性能。

HTTP 协议基础

HTTP(超文本传输协议)是Web的基础协议,浏览器通过HTTP请求资源并接收服务器响应。

HTTP 版本演进

  1. HTTP/1.0

    • 每个请求/响应都需要建立新的TCP连接
    • 支持基本的头部字段
    • 无法复用连接
  2. HTTP/1.1

    • 引入持久连接(keep-alive)
    • 引入管道化请求(pipelining)
    • 新增多种头部字段
    • 支持分块传输编码
  3. HTTP/2

    • 多路复用(multiplexing)
    • 头部压缩(HPACK)
    • 服务器推送
    • 二进制分帧层
  4. HTTP/3

    • 基于QUIC协议(基于UDP)
    • 减少连接建立时间
    • 改进拥塞控制
    • 连接迁移

浏览器如何发起HTTP请求

  1. 构建请求对象

    • 设置方法(GET、POST等)
    • 添加请求头
    • 准备请求体(如适用)
  2. DNS解析

    • 检查缓存
    • 递归查询DNS服务器
    • 解析域名为IP地址
  3. 建立连接

    • 创建TCP连接(HTTP/1.x和HTTP/2)
    • 或创建QUIC连接(HTTP/3)
    • 进行TLS握手(如使用HTTPS)
  4. 发送请求

    • 传输HTTP消息头
    • 传输HTTP消息体(如适用)
  5. 接收响应

    • 解析状态行
    • 处理响应头
    • 处理响应体

HTTP请求方法

浏览器支持多种HTTP方法,每种适用于不同场景:

方法描述典型用途
GET请求指定资源获取网页、图片、脚本等
POST提交数据表单提交、文件上传
HEAD仅请求头信息检查资源是否存在、校验缓存
PUT上传资源RESTful API中的资源更新
DELETE删除资源RESTful API中的资源删除
OPTIONS获取支持的方法CORS预检请求、API探测
PATCH部分更新资源RESTful API中的局部更新

HTTP状态码

浏览器根据响应状态码执行不同操作:

  • 1xx:信息性响应(请求已接收,继续处理)
  • 2xx:成功(请求已成功接收、理解和处理)
  • 3xx:重定向(需要进一步操作才能完成请求)
  • 4xx:客户端错误(请求包含错误或无法完成)
  • 5xx:服务器错误(服务器处理请求时出错)

常见状态码及浏览器行为:

状态码描述浏览器行为
200OK正常显示响应内容
301永久重定向缓存新地址并重定向
302临时重定向重定向但不缓存
304Not Modified使用本地缓存
404Not Found显示错误页面
500Server Error显示错误页面

浏览器缓存机制

浏览器缓存是提高Web性能的重要机制,通过重用之前获取的资源,减少网络请求。

缓存位置

浏览器缓存按优先级排序:

  1. 内存缓存

    • 存储在RAM中
    • 访问速度最快
    • 生命周期短(关闭标签页或浏览器后清除)
    • 通常用于当前会话使用的资源
  2. 磁盘缓存

    • 存储在硬盘上
    • 持久化存储
    • 容量比内存缓存大
    • 可以在浏览器会话之间保持
  3. Service Worker缓存

    • 通过JavaScript控制的缓存
    • 可编程性强
    • 支持离线访问
    • 独立于浏览器缓存
  4. Push缓存

    • HTTP/2服务器推送资源的缓存
    • 生命周期很短
    • 一般仅在会话中有效

缓存策略

浏览器实现两种主要的缓存策略:

强缓存

不需要向服务器发送请求,直接从缓存读取资源。通过以下头部控制:

  1. Expires(HTTP/1.0)

    Expires: Wed, 21 Oct 2023 07:28:00 GMT
    • 指定资源过期的绝对时间
    • 依赖客户端时间,可能不准确
    • 优先级低于Cache-Control
  2. Cache-Control(HTTP/1.1)

    Cache-Control: max-age=31536000
    • 指定资源有效期的相对时间(秒)
    • 更精确,不依赖客户端时间
    • 常用指令:
      • max-age:缓存有效时间
      • no-cache:强制验证缓存
      • no-store:禁止缓存
      • private:仅客户端缓存
      • public:允许中间缓存

协商缓存

当强缓存失效时,浏览器向服务器发送请求,服务器根据请求头判断是否使用缓存:

  1. Last-Modified / If-Modified-Since

    Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
    If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT
    • 基于资源的最后修改时间
    • 精度为秒级
    • 不适用于频繁变化的资源
  2. ETag / If-None-Match

    ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
    If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
    • 基于资源内容生成的唯一标识符
    • 更精确,不依赖时间
    • 计算ETag会消耗服务器资源

缓存流程

浏览器处理缓存的完整流程:

  1. 检查是否有强缓存命中

    • 解析Cache-Control/Expires头
    • 如命中,直接使用缓存资源(不发请求)
    • 如未命中,进入协商缓存阶段
  2. 协商缓存检查

    • 向服务器发送带有If-Modified-Since或If-None-Match头的请求
    • 服务器比较这些头与当前资源状态
    • 如资源未变化,返回304 Not Modified(不返回资源内容)
    • 如资源已变化,返回200 OK和新资源
  3. 缓存响应

    • 对于200响应,根据响应头更新缓存
    • 对于304响应,更新缓存元数据(如过期时间)

缓存控制指令详解

服务器响应头

Cache-Control: max-age=3600, must-revalidate, public
Expires: Wed, 21 Oct 2023 07:28:00 GMT
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
Vary: Accept-Encoding, User-Agent
  • must-revalidate:过期缓存必须验证才能使用
  • public:任何缓存都可以存储响应
  • private:只有浏览器可以缓存,中间代理不可缓存
  • no-cache:每次使用前必须验证缓存
  • no-store:完全禁止缓存
  • Vary:指定根据哪些请求头字段变化导致响应变化

客户端请求头

Cache-Control: max-age=0
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT
  • max-age=0:强制验证缓存
  • no-cache:忽略本地缓存,强制验证
  • no-store:禁止存储响应

按资源类型的缓存策略

不同类型的资源适用不同的缓存策略:

  1. HTML文档

    • 短期缓存或不缓存
    • 使用ETag进行验证
    Cache-Control: no-cache
  2. CSS和JavaScript

    • 长期缓存
    • 使用版本号或哈希值在文件名中
    Cache-Control: max-age=31536000, immutable
  3. 图片和媒体文件

    • 长期缓存
    • 文件名包含内容哈希
    Cache-Control: max-age=31536000
  4. API响应

    • 根据数据更新频率设置
    • 使用ETag进行验证
    Cache-Control: max-age=60, must-revalidate

浏览器网络优化技术

预加载和预连接

浏览器支持多种资源预加载机制:

  1. DNS预解析

    html
    <link rel="dns-prefetch" href="https://example.com">
  2. 预连接

    html
    <link rel="preconnect" href="https://example.com">
  3. 预加载

    html
    <link rel="preload" href="/styles.css" as="style">
  4. 预获取

    html
    <link rel="prefetch" href="/next-page.html">

HTTP/2和HTTP/3优化

现代浏览器利用新HTTP协议特性提高性能:

  1. 多路复用

    • 在单个连接上并行请求多个资源
    • 消除了HTTP/1.1的队头阻塞问题
  2. 头部压缩

    • 减少重复头部字段传输
    • 压缩头部数据
  3. 服务器推送

    • 主动推送关联资源
    • 减少客户端请求
  4. QUIC协议 (HTTP/3)

    • 建立连接更快
    • 更好的拥塞控制
    • 连接迁移支持

离线应用技术

浏览器提供多种技术实现离线Web应用:

  1. Service Worker

    • 拦截网络请求
    • 实现自定义缓存策略
    • 支持后台同步和推送通知
  2. 缓存API

    javascript
    // 在Service Worker中使用Cache API
    cache.addAll([
      '/',
      '/styles.css',
      '/script.js',
      '/images/logo.png'
    ]);
  3. IndexedDB

    • 存储大量结构化数据
    • 支持索引和查询
    • 适合离线应用数据存储
  4. Web应用清单(Web App Manifest)

    • 将网站添加到主屏幕
    • 定义离线体验

浏览器缓存调试技巧

开发者工具

使用浏览器开发者工具检查和调试缓存:

  1. Network面板

    • 检查请求/响应头
    • 查看缓存状态(Size列显示"(disk cache)"或"(memory cache)")
    • 分析资源加载时间
  2. 禁用缓存功能

    • Network面板中的"Disable cache"选项
    • 仅在开发者工具打开时生效
  3. 清除缓存

    • 使用Application面板中的Clear Storage功能
    • 或使用Ctrl+F5/Cmd+Shift+R强制刷新

常见缓存问题及解决方案

  1. 缓存过期日期不正确

    • 检查服务器时间配置
    • 确保正确设置Cache-Control或Expires头
  2. 缓存未更新

    • 使用内容哈希或版本号
    • 更改资源URL(如添加查询参数)
  3. 中间代理缓存问题

    • 使用Vary头控制缓存版本
    • 明确设置private或public指令
  4. 不一致的缓存行为

    • 确保所有资源使用一致的缓存策略
    • 监控和测试不同浏览器的缓存行为

浏览器缓存

浏览器缓存机制

  1. 强缓存:浏览器在本地缓存中查找资源,如果找到且未过期,则直接使用缓存资源,否则继续请求服务器。
  2. 协商缓存:浏览器在本地缓存中查找资源,如果找到且未过期,则向服务器发送请求,服务器验证资源是否更新,如果更新则返回新资源,否则返回304状态码,浏览器使用本地缓存资源。

浏览器缓存策略

  1. Cache-Control:控制缓存的策略,如max-age、no-cache、no-store等。
    1. max-age:指定缓存的过期时间,单位为秒。
    2. no-cache:表示每次请求都需要验证缓存是否有效。
    3. no-store:表示不缓存资源。
  2. Expires:指定缓存的过期时间,格式为GMT时间。
  3. ETag:资源的唯一标识符,用于验证缓存是否有效。
  4. Last-Modified:资源的最后修改时间,用于验证缓存是否有效。
  5. If-None-Match:客户端发送的ETag值,服务器根据该值判断资源是否更新。
  6. If-Modified-Since:客户端发送的Last-Modified值,服务器根据该值判断资源是否更新。
  7. Cache-Control优先级高于Expires,ETag优先级高于Last-Modified。
  8. 浏览器会根据Cache-Control、Expires、ETag、Last-Modified等字段来判断资源是否有效,如果有效则使用缓存资源,否则向服务器请求新资源。